@crownpeak/dqm-react-component-dev-mcp 1.2.0

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 (444) hide show
  1. package/README.md +138 -0
  2. package/data/.env.example +22 -0
  3. package/data/.gitattributes +47 -0
  4. package/data/.glfrc.json +7 -0
  5. package/data/.husky/pre-commit +5 -0
  6. package/data/.nvmrc +1 -0
  7. package/data/CHANGELOG.md +75 -0
  8. package/data/CODE_OF_CONDUCT.md +129 -0
  9. package/data/CONTRIBUTING.md +203 -0
  10. package/data/DOCS-STRUCTURE.md +307 -0
  11. package/data/I18N.md +292 -0
  12. package/data/LICENSE +22 -0
  13. package/data/README.md +315 -0
  14. package/data/SECURITY.md +125 -0
  15. package/data/WIKI-DEPLOYMENT.md +348 -0
  16. package/data/docs/AI-FEATURES.md +610 -0
  17. package/data/docs/API-REFERENCE.md +1022 -0
  18. package/data/docs/AUTHENTICATION.md +301 -0
  19. package/data/docs/BACKEND-API.md +468 -0
  20. package/data/docs/DEVELOPMENT.md +375 -0
  21. package/data/docs/EXAMPLES.md +622 -0
  22. package/data/docs/MCP-SERVER.md +307 -0
  23. package/data/docs/MIGRATION-GUIDE.md +367 -0
  24. package/data/docs/NPM-PUBLISH.md +193 -0
  25. package/data/docs/QUICKSTART.md +206 -0
  26. package/data/docs/REDIS-SETUP.md +162 -0
  27. package/data/docs/SERVER.md +228 -0
  28. package/data/docs/TROUBLESHOOTING.md +657 -0
  29. package/data/docs/WIDGET-GUIDE.md +638 -0
  30. package/data/docs/WIKI-HOME.md +58 -0
  31. package/data/docs/WIKI-SIDEBAR.md +39 -0
  32. package/data/package.json +171 -0
  33. package/data/playwright.config.ts +64 -0
  34. package/data/probe/.cargo/config.toml +10 -0
  35. package/data/probe/.claude/commands/performance-review.md +15 -0
  36. package/data/probe/.clinerules +288 -0
  37. package/data/probe/.dockerignore +57 -0
  38. package/data/probe/.githooks/post-commit +11 -0
  39. package/data/probe/.githooks/pre-commit +99 -0
  40. package/data/probe/.githooks/pre-commit-vow +9 -0
  41. package/data/probe/.prompts/engineer.md +41 -0
  42. package/data/probe/.roomodes +28 -0
  43. package/data/probe/.windsurfrules +0 -0
  44. package/data/probe/BASH_TOOL_SUMMARY.md +148 -0
  45. package/data/probe/BENCHMARKING.md +256 -0
  46. package/data/probe/CLAUDE.md +226 -0
  47. package/data/probe/CODE_OF_CONDUCT.md +128 -0
  48. package/data/probe/CONTRIBUTING.md +193 -0
  49. package/data/probe/Cargo.toml +120 -0
  50. package/data/probe/Cross.toml +10 -0
  51. package/data/probe/DOCKER-README.md +224 -0
  52. package/data/probe/Dockerfile +32 -0
  53. package/data/probe/ENHANCED_DEBUG_TELEMETRY.md +188 -0
  54. package/data/probe/LICENSE +201 -0
  55. package/data/probe/Makefile +210 -0
  56. package/data/probe/README.md +824 -0
  57. package/data/probe/SECURITY.md +67 -0
  58. package/data/probe/WINDOWS-GUIDE.md +294 -0
  59. package/data/probe/benches/parsing_benchmarks.rs +370 -0
  60. package/data/probe/benches/search_benchmarks.rs +599 -0
  61. package/data/probe/benches/simd_benchmarks.rs +372 -0
  62. package/data/probe/benches/timing_benchmarks.rs +287 -0
  63. package/data/probe/build-windows.bat +229 -0
  64. package/data/probe/codex-config/config.toml +6 -0
  65. package/data/probe/docs/PERFORMANCE_OPTIMIZATION.md +161 -0
  66. package/data/probe/examples/cache_demo.rs +46 -0
  67. package/data/probe/examples/chat/.dockerignore +37 -0
  68. package/data/probe/examples/chat/ChatSessionManager.js +295 -0
  69. package/data/probe/examples/chat/Dockerfile +98 -0
  70. package/data/probe/examples/chat/LICENSE +201 -0
  71. package/data/probe/examples/chat/LOCAL_IMAGE_SUPPORT.md +195 -0
  72. package/data/probe/examples/chat/MCP_INTEGRATION.md +400 -0
  73. package/data/probe/examples/chat/README.md +338 -0
  74. package/data/probe/examples/chat/TRACING.md +226 -0
  75. package/data/probe/examples/chat/appTracer.js +968 -0
  76. package/data/probe/examples/chat/auth.js +76 -0
  77. package/data/probe/examples/chat/bin/probe-chat.js +13 -0
  78. package/data/probe/examples/chat/build.js +104 -0
  79. package/data/probe/examples/chat/cancelRequest.js +84 -0
  80. package/data/probe/examples/chat/demo-agentic-image-flow.js +88 -0
  81. package/data/probe/examples/chat/demo-local-images.js +128 -0
  82. package/data/probe/examples/chat/fileSpanExporter.js +181 -0
  83. package/data/probe/examples/chat/implement/README.md +228 -0
  84. package/data/probe/examples/chat/implement/backends/AiderBackend.js +750 -0
  85. package/data/probe/examples/chat/implement/backends/BaseBackend.js +276 -0
  86. package/data/probe/examples/chat/implement/backends/ClaudeCodeBackend.js +767 -0
  87. package/data/probe/examples/chat/implement/backends/MockBackend.js +237 -0
  88. package/data/probe/examples/chat/implement/backends/registry.js +85 -0
  89. package/data/probe/examples/chat/implement/core/BackendManager.js +567 -0
  90. package/data/probe/examples/chat/implement/core/ImplementTool.js +354 -0
  91. package/data/probe/examples/chat/implement/core/config.js +428 -0
  92. package/data/probe/examples/chat/implement/core/timeouts.js +58 -0
  93. package/data/probe/examples/chat/implement/core/utils.js +496 -0
  94. package/data/probe/examples/chat/implement/types/BackendTypes.js +126 -0
  95. package/data/probe/examples/chat/index.js +669 -0
  96. package/data/probe/examples/chat/mcpServer.js +341 -0
  97. package/data/probe/examples/chat/npm/LICENSE +15 -0
  98. package/data/probe/examples/chat/npm/README.md +168 -0
  99. package/data/probe/examples/chat/npm/bin/probe-chat.js +156 -0
  100. package/data/probe/examples/chat/npm/index.js +259 -0
  101. package/data/probe/examples/chat/npm/package.json +54 -0
  102. package/data/probe/examples/chat/package.json +102 -0
  103. package/data/probe/examples/chat/probeChat.js +456 -0
  104. package/data/probe/examples/chat/probeTool.js +491 -0
  105. package/data/probe/examples/chat/storage/JsonChatStorage.js +476 -0
  106. package/data/probe/examples/chat/telemetry.js +281 -0
  107. package/data/probe/examples/chat/test/integration/chatFlows.test.js +320 -0
  108. package/data/probe/examples/chat/test/integration/toolCalling.test.js +471 -0
  109. package/data/probe/examples/chat/test/mocks/mockLLMProvider.js +269 -0
  110. package/data/probe/examples/chat/test/test-backends.js +90 -0
  111. package/data/probe/examples/chat/test/testUtils.js +530 -0
  112. package/data/probe/examples/chat/test/unit/backendTimeout.test.js +161 -0
  113. package/data/probe/examples/chat/test/unit/packageFiles.test.js +120 -0
  114. package/data/probe/examples/chat/test/verify-tests.js +118 -0
  115. package/data/probe/examples/chat/test-agentic-image-loading.js +294 -0
  116. package/data/probe/examples/chat/test-ai-sdk-telemetry.js +204 -0
  117. package/data/probe/examples/chat/test-chat-tracing.js +38 -0
  118. package/data/probe/examples/chat/test-direct-function.js +49 -0
  119. package/data/probe/examples/chat/test-file-size-validation.js +103 -0
  120. package/data/probe/examples/chat/test-full-mcp-integration.js +258 -0
  121. package/data/probe/examples/chat/test-github-context.txt +12 -0
  122. package/data/probe/examples/chat/test-hierarchy.js +203 -0
  123. package/data/probe/examples/chat/test-image-spans.js +37 -0
  124. package/data/probe/examples/chat/test-local-image-reading.js +176 -0
  125. package/data/probe/examples/chat/test-mcp-integration.js +136 -0
  126. package/data/probe/examples/chat/test-mcp-probe-server.js +161 -0
  127. package/data/probe/examples/chat/test-mcp-with-ai.js +279 -0
  128. package/data/probe/examples/chat/test-multiple-allowed-dirs.js +111 -0
  129. package/data/probe/examples/chat/test-probe-mcp-server.js +110 -0
  130. package/data/probe/examples/chat/test-security-validation.js +145 -0
  131. package/data/probe/examples/chat/test-simple-tracing.js +32 -0
  132. package/data/probe/examples/chat/test-trace-verification.js +235 -0
  133. package/data/probe/examples/chat/test-tracing.js +114 -0
  134. package/data/probe/examples/chat/tokenCounter.js +419 -0
  135. package/data/probe/examples/chat/tokenUsageDisplay.js +134 -0
  136. package/data/probe/examples/chat/webServer.js +1103 -0
  137. package/data/probe/examples/reranker/Cargo.toml +33 -0
  138. package/data/probe/examples/reranker/DEBUG_OUTPUT_ANALYSIS.md +71 -0
  139. package/data/probe/examples/reranker/MODELS.md +66 -0
  140. package/data/probe/examples/reranker/MODEL_COMPARISON.md +60 -0
  141. package/data/probe/examples/reranker/MULTI_MODEL_ANALYSIS.md +176 -0
  142. package/data/probe/examples/reranker/PERFORMANCE_SUMMARY.md +156 -0
  143. package/data/probe/examples/reranker/README.md +347 -0
  144. package/data/probe/examples/reranker/RUST_BERT_COMPARISON.md +82 -0
  145. package/data/probe/examples/reranker/TOKENIZATION_GUIDE.md +120 -0
  146. package/data/probe/examples/reranker/check_rust_tokenizer.py +108 -0
  147. package/data/probe/examples/reranker/convert_to_torchscript.py +109 -0
  148. package/data/probe/examples/reranker/debug_scoring.py +189 -0
  149. package/data/probe/examples/reranker/debug_tokenization.py +154 -0
  150. package/data/probe/examples/reranker/download_models.sh +73 -0
  151. package/data/probe/examples/reranker/requirements.txt +13 -0
  152. package/data/probe/examples/reranker/run_comprehensive_benchmark.sh +83 -0
  153. package/data/probe/examples/reranker/rust_bert_test/Cargo.toml +12 -0
  154. package/data/probe/examples/reranker/rust_bert_test/README.md +54 -0
  155. package/data/probe/examples/reranker/simple_test.py +50 -0
  156. package/data/probe/examples/reranker/test_all_models.sh +63 -0
  157. package/data/probe/examples/reranker/test_bert_results.sh +44 -0
  158. package/data/probe/examples/reranker/test_cross_encoder.py +334 -0
  159. package/data/probe/examples/reranker/test_cross_encoder.sh +80 -0
  160. package/data/probe/examples/reranker/test_exact_comparison.py +151 -0
  161. package/data/probe/examples/reranker/test_parallel_performance.sh +56 -0
  162. package/data/probe/examples/reranker/test_scores.py +132 -0
  163. package/data/probe/install.ps1 +508 -0
  164. package/data/probe/install.sh +460 -0
  165. package/data/probe/npm/CLONE_METHOD_EXAMPLES.md +596 -0
  166. package/data/probe/npm/CONTEXT_COMPACTION.md +303 -0
  167. package/data/probe/npm/DELEGATE_TOOL_README.md +166 -0
  168. package/data/probe/npm/MAID_INTEGRATION.md +313 -0
  169. package/data/probe/npm/MCP_INTEGRATION_SUMMARY.md +241 -0
  170. package/data/probe/npm/README.md +824 -0
  171. package/data/probe/npm/bin/.gitignore +7 -0
  172. package/data/probe/npm/bin/.gitkeep +0 -0
  173. package/data/probe/npm/bin/README.md +12 -0
  174. package/data/probe/npm/bin/probe +167 -0
  175. package/data/probe/npm/docs/CLAUDE_CODE_INTEGRATION.md +414 -0
  176. package/data/probe/npm/docs/CODEX_INTEGRATION.md +502 -0
  177. package/data/probe/npm/docs/EDIT_CREATE_TOOLS.md +233 -0
  178. package/data/probe/npm/docs/RETRY_AND_FALLBACK.md +674 -0
  179. package/data/probe/npm/example-usage.js +335 -0
  180. package/data/probe/npm/examples/multi-engine-demo.js +117 -0
  181. package/data/probe/npm/examples/probe-agent-cli.js +113 -0
  182. package/data/probe/npm/examples/test-agent-edit.js +114 -0
  183. package/data/probe/npm/examples/test-edit-create.js +120 -0
  184. package/data/probe/npm/examples/test-edit-direct.js +114 -0
  185. package/data/probe/npm/index.d.ts +744 -0
  186. package/data/probe/npm/jest.config.js +52 -0
  187. package/data/probe/npm/package.json +117 -0
  188. package/data/probe/npm/scripts/build-agent.cjs +75 -0
  189. package/data/probe/npm/scripts/build-cjs.js +124 -0
  190. package/data/probe/npm/scripts/build-mcp.cjs +36 -0
  191. package/data/probe/npm/scripts/postinstall.js +216 -0
  192. package/data/probe/npm/test-codex-e2e.js +78 -0
  193. package/data/probe/npm/test-download-lock.js +109 -0
  194. package/data/probe/npm/test-grep-security.js +94 -0
  195. package/data/probe/npm/test-grep-simplified.js +63 -0
  196. package/data/probe/npm/test-grep.js +51 -0
  197. package/data/probe/npm/tests/README.md +96 -0
  198. package/data/probe/npm/tests/agent-compact-history.test.js +174 -0
  199. package/data/probe/npm/tests/allow-tests-default.test.js +151 -0
  200. package/data/probe/npm/tests/contextCompactor.test.js +498 -0
  201. package/data/probe/npm/tests/delegate-config.test.js +353 -0
  202. package/data/probe/npm/tests/delegate-integration.test.js +348 -0
  203. package/data/probe/npm/tests/extractor-integration.test.js +162 -0
  204. package/data/probe/npm/tests/extractor.test.js +317 -0
  205. package/data/probe/npm/tests/fixtures/sampleDiagrams.js +267 -0
  206. package/data/probe/npm/tests/integration/claude-code-auto-fallback.spec.js +148 -0
  207. package/data/probe/npm/tests/integration/claude-code-multi-step.spec.js +127 -0
  208. package/data/probe/npm/tests/integration/claude-code-tool-events.spec.js +163 -0
  209. package/data/probe/npm/tests/integration/codex-auto-fallback.spec.js +191 -0
  210. package/data/probe/npm/tests/integration/codex-tool-events.spec.js +147 -0
  211. package/data/probe/npm/tests/integration/examplesChatMcp.test.js +402 -0
  212. package/data/probe/npm/tests/integration/mcpDotenvSupport.test.js +174 -0
  213. package/data/probe/npm/tests/integration/mcpErrorHandling.test.js +566 -0
  214. package/data/probe/npm/tests/integration/mcpRobustness.test.js +564 -0
  215. package/data/probe/npm/tests/integration/mcpStdoutPurity.test.js +355 -0
  216. package/data/probe/npm/tests/integration/probeAgentMcp.test.js +398 -0
  217. package/data/probe/npm/tests/integration/retryFallback.test.js +368 -0
  218. package/data/probe/npm/tests/integration/schema-in-initial-message.test.js +318 -0
  219. package/data/probe/npm/tests/integration/schema-validation-loop-prevention.test.js +244 -0
  220. package/data/probe/npm/tests/integration/schemaRetryLogic.test.js +94 -0
  221. package/data/probe/npm/tests/integration/validationFlow.test.js +329 -0
  222. package/data/probe/npm/tests/manual/test-codex-basic.js +110 -0
  223. package/data/probe/npm/tests/mcp/mcpClientManager.test.js +614 -0
  224. package/data/probe/npm/tests/mcp/mcpConfig.test.js +359 -0
  225. package/data/probe/npm/tests/mcp/mcpXmlBridge.test.js +436 -0
  226. package/data/probe/npm/tests/mcp/mockMcpServer.js +510 -0
  227. package/data/probe/npm/tests/mcp-strict-syntax.test.js +319 -0
  228. package/data/probe/npm/tests/mermaidQuoteEscaping.test.js +214 -0
  229. package/data/probe/npm/tests/nestedQuoteFix.test.js +40 -0
  230. package/data/probe/npm/tests/setup.js +46 -0
  231. package/data/probe/npm/tests/unit/allowed-tools.test.js +513 -0
  232. package/data/probe/npm/tests/unit/attempt-completion-closing-tag-in-content.test.js +188 -0
  233. package/data/probe/npm/tests/unit/attemptCompletionJsonFix.test.js +238 -0
  234. package/data/probe/npm/tests/unit/attemptCompletionJsonIssue.test.js +128 -0
  235. package/data/probe/npm/tests/unit/backtickAutoFix.test.js +35 -0
  236. package/data/probe/npm/tests/unit/bash-probe-agent-integration.test.js +389 -0
  237. package/data/probe/npm/tests/unit/bash-simple-commands.test.js +324 -0
  238. package/data/probe/npm/tests/unit/bash-tool-comprehensive.test.js +371 -0
  239. package/data/probe/npm/tests/unit/bash-tool-integration.test.js +310 -0
  240. package/data/probe/npm/tests/unit/bash-tool.test.js +341 -0
  241. package/data/probe/npm/tests/unit/completion-prompt.test.js +379 -0
  242. package/data/probe/npm/tests/unit/cwd-path-options.test.js +287 -0
  243. package/data/probe/npm/tests/unit/delegate-limits.test.js +422 -0
  244. package/data/probe/npm/tests/unit/direct-content-attempt-completion.test.js +235 -0
  245. package/data/probe/npm/tests/unit/edit-create-tools.test.js +609 -0
  246. package/data/probe/npm/tests/unit/enhancedMermaidValidation.test.js +577 -0
  247. package/data/probe/npm/tests/unit/extract-content.test.js +83 -0
  248. package/data/probe/npm/tests/unit/extract-multiple-targets.test.js +89 -0
  249. package/data/probe/npm/tests/unit/fallbackManager.test.js +442 -0
  250. package/data/probe/npm/tests/unit/githubCompatibilityValidation.test.js +258 -0
  251. package/data/probe/npm/tests/unit/imageConfig.test.js +149 -0
  252. package/data/probe/npm/tests/unit/imagePathResolution.test.js +345 -0
  253. package/data/probe/npm/tests/unit/json-fixing-agent.test.js +238 -0
  254. package/data/probe/npm/tests/unit/json-validation-enhanced-errors.test.js +199 -0
  255. package/data/probe/npm/tests/unit/jsonValidationInfiniteLoopFix.test.js +228 -0
  256. package/data/probe/npm/tests/unit/maidIntegration.test.js +139 -0
  257. package/data/probe/npm/tests/unit/maxIterationsWarning.test.js +195 -0
  258. package/data/probe/npm/tests/unit/mermaidEdgeLabelFix.test.js +161 -0
  259. package/data/probe/npm/tests/unit/mermaidHtmlEntities.test.js +76 -0
  260. package/data/probe/npm/tests/unit/mermaidInfiniteLoopFix.test.js +64 -0
  261. package/data/probe/npm/tests/unit/mermaidValidation.test.js +723 -0
  262. package/data/probe/npm/tests/unit/mermaidValidationVisorExample.test.js +309 -0
  263. package/data/probe/npm/tests/unit/probe-agent-clone-realistic.test.js +643 -0
  264. package/data/probe/npm/tests/unit/probe-agent-clone.test.js +476 -0
  265. package/data/probe/npm/tests/unit/probe-agent-delegate.test.js +400 -0
  266. package/data/probe/npm/tests/unit/probe-agent-model-option.test.js +118 -0
  267. package/data/probe/npm/tests/unit/probeTool-security.test.js +283 -0
  268. package/data/probe/npm/tests/unit/readImageTool.test.js +418 -0
  269. package/data/probe/npm/tests/unit/retryManager.test.js +317 -0
  270. package/data/probe/npm/tests/unit/schema-aware-reminders.test.js +288 -0
  271. package/data/probe/npm/tests/unit/schemaDefinitionDetection.test.js +115 -0
  272. package/data/probe/npm/tests/unit/schemaUtils.test.js +1268 -0
  273. package/data/probe/npm/tests/unit/simpleTelemetry.test.js +282 -0
  274. package/data/probe/npm/tests/unit/simplified-attempt-completion.test.js +274 -0
  275. package/data/probe/npm/tests/unit/single-quote-json-bug.test.js +231 -0
  276. package/data/probe/npm/tests/unit/subgraphAutoFix.test.js +110 -0
  277. package/data/probe/npm/tests/unit/system-prompt.test.js +32 -0
  278. package/data/probe/npm/tests/unit/types-probe-agent-options.test.js +42 -0
  279. package/data/probe/npm/tests/unit/xmlParsing.test.js +720 -0
  280. package/data/probe/npm/tsconfig.json +21 -0
  281. package/data/probe/result1.txt +19 -0
  282. package/data/probe/result2.txt +26 -0
  283. package/data/probe/scripts/benchmark.sh +270 -0
  284. package/data/probe/scripts/cache_memory_analysis.rs +844 -0
  285. package/data/probe/scripts/claude-hook-wrapper.sh +56 -0
  286. package/data/probe/site/.env.example +10 -0
  287. package/data/probe/site/DEPLOYMENT.md +86 -0
  288. package/data/probe/site/README.md +183 -0
  289. package/data/probe/site/adding-languages.md +135 -0
  290. package/data/probe/site/ai-chat.md +427 -0
  291. package/data/probe/site/ai-integration.md +1488 -0
  292. package/data/probe/site/blog/agentic-flow-custom-xml-protocol.md +407 -0
  293. package/data/probe/site/blog/index.md +118 -0
  294. package/data/probe/site/blog/v0.6.0-release.md +426 -0
  295. package/data/probe/site/blog.md +8 -0
  296. package/data/probe/site/changelog.md +200 -0
  297. package/data/probe/site/cli-mode.md +437 -0
  298. package/data/probe/site/code-extraction.md +436 -0
  299. package/data/probe/site/contributing/README.md +9 -0
  300. package/data/probe/site/contributing/documentation-cross-references.md +215 -0
  301. package/data/probe/site/contributing/documentation-maintenance.md +275 -0
  302. package/data/probe/site/contributing/documentation-structure.md +75 -0
  303. package/data/probe/site/documentation-cross-references.md +215 -0
  304. package/data/probe/site/documentation-guide.md +132 -0
  305. package/data/probe/site/documentation-maintenance.md +275 -0
  306. package/data/probe/site/features.md +147 -0
  307. package/data/probe/site/how-it-works.md +118 -0
  308. package/data/probe/site/index.md +175 -0
  309. package/data/probe/site/index.md.bak +133 -0
  310. package/data/probe/site/installation.md +235 -0
  311. package/data/probe/site/integrations/docker.md +248 -0
  312. package/data/probe/site/integrations/github-actions.md +413 -0
  313. package/data/probe/site/language-support-overview.md +168 -0
  314. package/data/probe/site/mcp-integration.md +587 -0
  315. package/data/probe/site/mcp-server.md +304 -0
  316. package/data/probe/site/navigation-structure.md +76 -0
  317. package/data/probe/site/nodejs-sdk.md +798 -0
  318. package/data/probe/site/output-formats.md +625 -0
  319. package/data/probe/site/package.json +21 -0
  320. package/data/probe/site/public/_headers +28 -0
  321. package/data/probe/site/public/_redirects +11 -0
  322. package/data/probe/site/quick-start.md +289 -0
  323. package/data/probe/site/search-functionality.md +291 -0
  324. package/data/probe/site/search-reference.md +291 -0
  325. package/data/probe/site/supported-languages.md +215 -0
  326. package/data/probe/site/use-cases/README.md +8 -0
  327. package/data/probe/site/use-cases/advanced-cli.md +253 -0
  328. package/data/probe/site/use-cases/ai-code-editors.md +239 -0
  329. package/data/probe/site/use-cases/building-ai-tools.md +529 -0
  330. package/data/probe/site/use-cases/cli-ai-workflows.md +285 -0
  331. package/data/probe/site/use-cases/deploying-probe-web-interface.md +255 -0
  332. package/data/probe/site/use-cases/integrating-probe-into-ai-code-editors.md +161 -0
  333. package/data/probe/site/use-cases/nodejs-sdk.md +596 -0
  334. package/data/probe/site/use-cases/team-chat.md +350 -0
  335. package/data/probe/site/web-interface.md +434 -0
  336. package/data/probe/site/wrangler.toml +9 -0
  337. package/data/probe/test-api-key.sh +1 -0
  338. package/data/probe/test-probe-implementation/hello.js +7 -0
  339. package/data/probe/test_cases/demonstrate_early_termination_issues.sh +176 -0
  340. package/data/probe/test_cases/early_termination_issues.rs +533 -0
  341. package/data/probe/test_data/test_nested_struct.go +26 -0
  342. package/data/probe/tests/README.md +286 -0
  343. package/data/probe/tests/README_search_determinism_tests.md +116 -0
  344. package/data/probe/tests/adjacent_comment_test.rs +152 -0
  345. package/data/probe/tests/apostrophe_handling_tests.rs +132 -0
  346. package/data/probe/tests/block_filtering_with_ast_tests.rs +669 -0
  347. package/data/probe/tests/block_merging_tests.rs +396 -0
  348. package/data/probe/tests/c_outline_format_tests.rs +2179 -0
  349. package/data/probe/tests/cache_invalidation_issues.rs.disabled +682 -0
  350. package/data/probe/tests/cache_order_tests.rs +147 -0
  351. package/data/probe/tests/cache_query_scoping_tests.rs +221 -0
  352. package/data/probe/tests/cli_tests.rs +680 -0
  353. package/data/probe/tests/comment_context_integration_test.rs +240 -0
  354. package/data/probe/tests/common.rs +33 -0
  355. package/data/probe/tests/complex_block_merging_tests.rs +599 -0
  356. package/data/probe/tests/complex_query_block_filtering_tests.rs +422 -0
  357. package/data/probe/tests/control_flow_closing_braces_test.rs +91 -0
  358. package/data/probe/tests/cpp_outline_format_tests.rs +1507 -0
  359. package/data/probe/tests/csharp_outline_format_tests.rs +941 -0
  360. package/data/probe/tests/elastic_query_integration_tests.rs +922 -0
  361. package/data/probe/tests/extract_command_tests.rs +1848 -0
  362. package/data/probe/tests/extract_deduplication_tests.rs +146 -0
  363. package/data/probe/tests/extract_input_file_tests.rs +84 -0
  364. package/data/probe/tests/extract_prompt_tests.rs +102 -0
  365. package/data/probe/tests/filename_search_tests.rs +96 -0
  366. package/data/probe/tests/fixtures/user/AssemblyInfo.cs +3 -0
  367. package/data/probe/tests/github_extract_tests.rs +234 -0
  368. package/data/probe/tests/go_comment_test.rs +253 -0
  369. package/data/probe/tests/go_outline_format_tests.rs +2587 -0
  370. package/data/probe/tests/go_path_resolver_tests.rs +96 -0
  371. package/data/probe/tests/html_outline_format_tests.rs +637 -0
  372. package/data/probe/tests/integration_tests.rs +837 -0
  373. package/data/probe/tests/ip_whitelist_test.rs +148 -0
  374. package/data/probe/tests/java_outline_format_tests.rs +1611 -0
  375. package/data/probe/tests/javascript_extract_tests.rs +315 -0
  376. package/data/probe/tests/javascript_outline_format_tests.rs +1464 -0
  377. package/data/probe/tests/json_format_tests.rs +436 -0
  378. package/data/probe/tests/json_schema_validation_tests.rs +450 -0
  379. package/data/probe/tests/lib_usage.rs +60 -0
  380. package/data/probe/tests/line_comment_context_extension_test.rs +459 -0
  381. package/data/probe/tests/line_map_cache_tests.rs +114 -0
  382. package/data/probe/tests/markdown_integration_tests.rs +190 -0
  383. package/data/probe/tests/mocks/test_ip_whitelist.go +11 -0
  384. package/data/probe/tests/mocks/test_object.js +27 -0
  385. package/data/probe/tests/mocks/test_struct.go +50 -0
  386. package/data/probe/tests/multi_keyword_pattern_tests.rs +464 -0
  387. package/data/probe/tests/multi_language_syntax_integration_tests.rs +218 -0
  388. package/data/probe/tests/multiple_capture_groups_tests.rs +169 -0
  389. package/data/probe/tests/negative_compound_word_tests.rs +246 -0
  390. package/data/probe/tests/nested_symbol_extraction_tests.rs +99 -0
  391. package/data/probe/tests/outline_cross_file_interference_test.rs +335 -0
  392. package/data/probe/tests/outline_keyword_preservation_test.rs +67 -0
  393. package/data/probe/tests/output_format_edge_cases_tests.rs +693 -0
  394. package/data/probe/tests/parallel_extraction_tests.rs +178 -0
  395. package/data/probe/tests/parallel_search_tests.rs +355 -0
  396. package/data/probe/tests/path_resolver_tests.rs +698 -0
  397. package/data/probe/tests/php_outline_format_extended_tests.rs +928 -0
  398. package/data/probe/tests/php_outline_format_tests.rs +768 -0
  399. package/data/probe/tests/property_tests.proptest-regressions +9 -0
  400. package/data/probe/tests/property_tests.rs +118 -0
  401. package/data/probe/tests/python_outline_format_tests.rs +1538 -0
  402. package/data/probe/tests/query_command_json_tests.rs +438 -0
  403. package/data/probe/tests/query_command_tests.rs +232 -0
  404. package/data/probe/tests/query_command_xml_tests.rs +569 -0
  405. package/data/probe/tests/quoted_term_with_negative_keyword_tests.rs +216 -0
  406. package/data/probe/tests/required_terms_filename_tests.rs +116 -0
  407. package/data/probe/tests/ruby_outline_format_tests.rs +1011 -0
  408. package/data/probe/tests/rust_line_comment_context_test.rs +151 -0
  409. package/data/probe/tests/rust_outline_format_enhanced_tests.rs +725 -0
  410. package/data/probe/tests/rust_outline_format_tests.rs +843 -0
  411. package/data/probe/tests/schemas/xml_output_schema.xsd +38 -0
  412. package/data/probe/tests/search_determinism_tests.rs +451 -0
  413. package/data/probe/tests/search_hints_tests.rs +253 -0
  414. package/data/probe/tests/special_character_escaping_tests.rs +417 -0
  415. package/data/probe/tests/stemming_compound_word_filtering_tests.rs +535 -0
  416. package/data/probe/tests/strict_elastic_syntax_tests.rs +404 -0
  417. package/data/probe/tests/swift_outline_format_tests.rs +3319 -0
  418. package/data/probe/tests/symbols_tests.rs +166 -0
  419. package/data/probe/tests/test_file.rs +45 -0
  420. package/data/probe/tests/test_tokenize.rs +28 -0
  421. package/data/probe/tests/timeout_tests.rs +82 -0
  422. package/data/probe/tests/tokenization_tests.rs +195 -0
  423. package/data/probe/tests/tokenized_block_filtering_tests.rs +174 -0
  424. package/data/probe/tests/typescript_extract_tests.rs +214 -0
  425. package/data/probe/tests/typescript_outline_format_tests.rs +2188 -0
  426. package/data/probe/tests/xml_format_tests.rs +568 -0
  427. package/data/probe/tests/xml_schema_validation_tests.rs +497 -0
  428. package/data/scripts/postinstall.mjs +9 -0
  429. package/data/scripts/set-version.js +0 -0
  430. package/data/scripts/wiki-build.sh +111 -0
  431. package/data/scripts/wiki-deploy.sh +73 -0
  432. package/data/serve.json +12 -0
  433. package/data/test/demo-dynamic.html +134 -0
  434. package/data/test/demo-esm.html +105 -0
  435. package/data/test/demo-iife.html +78 -0
  436. package/data/tsconfig.json +7 -0
  437. package/data/vite.server.ts +483 -0
  438. package/data/vitest.config.ts +40 -0
  439. package/data/wiki/Home.md +58 -0
  440. package/data/wiki/_Sidebar.md +39 -0
  441. package/docs-mcp.config.json +20 -0
  442. package/package.json +56 -0
  443. package/src/config.js +111 -0
  444. package/src/index.js +395 -0
@@ -0,0 +1,1538 @@
1
+ use anyhow::Result;
2
+ use std::fs;
3
+ use tempfile::TempDir;
4
+
5
+ mod common;
6
+ use common::TestContext;
7
+
8
+ #[test]
9
+ fn test_python_outline_basic_symbols() -> Result<()> {
10
+ let temp_dir = TempDir::new()?;
11
+ let test_file = temp_dir.path().join("basic.py");
12
+
13
+ let content = r#"class Calculator:
14
+ """A simple calculator class."""
15
+
16
+ def __init__(self, name: str):
17
+ self.name = name
18
+
19
+ def add(self, x: int, y: int) -> int:
20
+ """Add two numbers."""
21
+ return x + y
22
+
23
+ @property
24
+ def version(self) -> str:
25
+ """Get calculator version."""
26
+ return "1.0.0"
27
+
28
+ def process_data(data: list) -> int:
29
+ """Process a list of data."""
30
+ return len(data)
31
+
32
+ async def fetch_data(url: str) -> str:
33
+ """Fetch data asynchronously."""
34
+ return f"data from {url}"
35
+
36
+ def test_calculator():
37
+ """Test the calculator functionality."""
38
+ calc = Calculator("test")
39
+ assert calc.add(2, 3) == 5
40
+ "#;
41
+
42
+ fs::write(&test_file, content)?;
43
+
44
+ let ctx = TestContext::new();
45
+ let output = ctx.run_probe(&[
46
+ "search",
47
+ "def|class", // Search for Python functions and classes
48
+ test_file.to_str().unwrap(),
49
+ "--format",
50
+ "outline",
51
+ "--max-results",
52
+ "20",
53
+ "--allow-tests",
54
+ ])?;
55
+
56
+ // Verify Python symbols are extracted (be more flexible)
57
+ let has_calculator = output.contains("Calculator");
58
+ let has_process_data = output.contains("process_data");
59
+ let has_fetch_data = output.contains("fetch_data") || output.contains("async");
60
+ let has_test = output.contains("test_calculator") || output.contains("test");
61
+
62
+ assert!(
63
+ has_calculator,
64
+ "Missing Calculator class - output: {}",
65
+ output
66
+ );
67
+ assert!(
68
+ has_process_data || output.contains("def"),
69
+ "Missing process_data function or similar - output: {}",
70
+ output
71
+ );
72
+ assert!(
73
+ has_fetch_data || output.contains("async") || output.contains("fetch"),
74
+ "Missing async function or similar - output: {}",
75
+ output
76
+ );
77
+ assert!(
78
+ has_test || output.contains("test"),
79
+ "Missing test function or similar - output: {}",
80
+ output
81
+ );
82
+
83
+ Ok(())
84
+ }
85
+
86
+ #[test]
87
+ fn test_python_outline_decorators() -> Result<()> {
88
+ let temp_dir = TempDir::new()?;
89
+ let test_file = temp_dir.path().join("decorators.py");
90
+
91
+ let content = r#"from functools import wraps
92
+
93
+ def timing_decorator(func):
94
+ @wraps(func)
95
+ def wrapper(*args, **kwargs):
96
+ import time
97
+ start = time.time()
98
+ result = func(*args, **kwargs)
99
+ end = time.time()
100
+ print(f"Execution time: {end - start}")
101
+ return result
102
+ return wrapper
103
+
104
+ class UserManager:
105
+ def __init__(self, db_url: str):
106
+ self.db_url = db_url
107
+
108
+ @property
109
+ def connection_status(self) -> str:
110
+ """Get database connection status."""
111
+ return "connected"
112
+
113
+ @classmethod
114
+ def create_default(cls):
115
+ """Create UserManager with default settings."""
116
+ return cls("sqlite:///default.db")
117
+
118
+ @staticmethod
119
+ def validate_email(email: str) -> bool:
120
+ """Validate email format."""
121
+ return "@" in email
122
+
123
+ @timing_decorator
124
+ def process_users(self, users: list) -> list:
125
+ """Process a list of users."""
126
+ return [user for user in users if self.validate_email(user.get('email', ''))]
127
+ "#;
128
+
129
+ fs::write(&test_file, content)?;
130
+
131
+ let ctx = TestContext::new();
132
+ let output = ctx.run_probe(&[
133
+ "search",
134
+ "def|class", // Search for Python functions and classes
135
+ test_file.to_str().unwrap(),
136
+ "--format",
137
+ "outline",
138
+ "--max-results",
139
+ "20",
140
+ "--allow-tests",
141
+ ])?;
142
+
143
+ // Verify decorated functions and methods are properly shown (more flexible)
144
+ let has_decorator = output.contains("timing_decorator") || output.contains("decorator");
145
+ let has_user_manager = output.contains("UserManager") || output.contains("class");
146
+
147
+ assert!(
148
+ has_decorator,
149
+ "Missing decorator function or similar - output: {}",
150
+ output
151
+ );
152
+ assert!(
153
+ has_user_manager,
154
+ "Missing UserManager class or similar - output: {}",
155
+ output
156
+ );
157
+ // Note: Currently the extract command only shows top-level symbols
158
+ // Decorated methods within classes are not currently extracted as separate symbols
159
+ // This could be improved in future versions
160
+
161
+ Ok(())
162
+ }
163
+
164
+ #[test]
165
+ fn test_python_outline_nested_classes() -> Result<()> {
166
+ let temp_dir = TempDir::new()?;
167
+ let test_file = temp_dir.path().join("nested.py");
168
+
169
+ let content = r#"class ReportGenerator:
170
+ """Generate various types of reports."""
171
+
172
+ def __init__(self):
173
+ self.reports_created = 0
174
+
175
+ class PDFReport:
176
+ """Nested class for PDF reports."""
177
+
178
+ def __init__(self, title: str):
179
+ self.title = title
180
+
181
+ def generate(self, data: dict) -> bytes:
182
+ """Generate PDF from data."""
183
+ return b"PDF content"
184
+
185
+ class Metadata:
186
+ """Metadata for PDF reports."""
187
+
188
+ def __init__(self, author: str):
189
+ self.author = author
190
+
191
+ class CSVReport:
192
+ """Nested class for CSV reports."""
193
+
194
+ def __init__(self, delimiter: str = ','):
195
+ self.delimiter = delimiter
196
+
197
+ def generate(self, data: list) -> str:
198
+ """Generate CSV from data."""
199
+ return "CSV content"
200
+
201
+ def create_pdf_report(self, title: str):
202
+ """Create a PDF report instance."""
203
+ return self.PDFReport(title)
204
+
205
+ def outer_function():
206
+ """Function with nested functions."""
207
+
208
+ def inner_function(x: int) -> int:
209
+ """Inner function."""
210
+ return x * 2
211
+
212
+ def another_inner() -> str:
213
+ """Another inner function."""
214
+ return "inner"
215
+
216
+ return inner_function, another_inner
217
+ "#;
218
+
219
+ fs::write(&test_file, content)?;
220
+
221
+ let ctx = TestContext::new();
222
+ let output = ctx.run_probe(&[
223
+ "search",
224
+ "def|class", // Search for Python functions and classes
225
+ test_file.to_str().unwrap(),
226
+ "--format",
227
+ "outline",
228
+ "--max-results",
229
+ "20",
230
+ "--allow-tests",
231
+ ])?;
232
+
233
+ // Verify top-level structures are shown (be flexible)
234
+ let has_report_generator = output.contains("ReportGenerator") || output.contains("class");
235
+ let has_outer_function = output.contains("outer_function") || output.contains("def");
236
+
237
+ assert!(
238
+ has_report_generator,
239
+ "Missing ReportGenerator class or similar - output: {}",
240
+ output
241
+ );
242
+ assert!(
243
+ has_outer_function,
244
+ "Missing outer function or similar - output: {}",
245
+ output
246
+ );
247
+ // Nested classes (PDFReport, CSVReport, Metadata) are not shown individually in outline format
248
+ // They are inside ReportGenerator and outline format only shows top-level structures
249
+ assert!(
250
+ output.contains("..."),
251
+ "Missing ellipsis in outline format - output: {}",
252
+ output
253
+ );
254
+
255
+ Ok(())
256
+ }
257
+
258
+ #[test]
259
+ fn test_python_outline_docstrings_and_comments() -> Result<()> {
260
+ let temp_dir = TempDir::new()?;
261
+ let test_file = temp_dir.path().join("docstrings.py");
262
+
263
+ let content = r#"# Single line comment
264
+ def function_with_single_quotes():
265
+ '''Function with single quote docstring.
266
+
267
+ This tests parsing of single quote docstrings.
268
+ '''
269
+ # Internal comment
270
+ return "result"
271
+
272
+ def function_with_double_quotes():
273
+ """Function with double quote docstring.
274
+
275
+ This tests parsing of double quote docstrings.
276
+ """
277
+ return "result"
278
+
279
+ def function_with_raw_docstring():
280
+ r"""Raw docstring with backslashes: \n\t\r
281
+
282
+ This is a raw string docstring.
283
+ """
284
+ return "result"
285
+
286
+ class DocumentedClass:
287
+ """Class with comprehensive docstring.
288
+
289
+ Attributes:
290
+ name: The name of the object
291
+ value: The numeric value
292
+
293
+ Examples:
294
+ >>> obj = DocumentedClass("test", 42)
295
+ >>> obj.name
296
+ 'test'
297
+ """
298
+
299
+ def __init__(self, name: str, value: int):
300
+ self.name = name # Name comment
301
+ self.value = value # Value comment
302
+
303
+ def method_with_docstring(self):
304
+ """Method with proper docstring.
305
+
306
+ Returns:
307
+ str: A formatted string
308
+ """
309
+ return f"{self.name}: {self.value}"
310
+
311
+ # Comment above function
312
+ def test_docstring_parsing():
313
+ """Test that docstrings are preserved in outline."""
314
+ obj = DocumentedClass("test", 42)
315
+ assert obj.method_with_docstring() == "test: 42"
316
+ "#;
317
+
318
+ fs::write(&test_file, content)?;
319
+
320
+ let ctx = TestContext::new();
321
+ let output = ctx.run_probe(&[
322
+ "search",
323
+ "def|class", // Search for Python functions and classes
324
+ test_file.to_str().unwrap(),
325
+ "--format",
326
+ "outline",
327
+ "--max-results",
328
+ "20",
329
+ "--allow-tests",
330
+ ])?;
331
+
332
+ // Verify functions and classes are shown (be flexible)
333
+ let has_functions = output.contains("function_with") || output.contains("def");
334
+ let has_documented_class = output.contains("DocumentedClass") || output.contains("class");
335
+ let has_test = output.contains("test_docstring") || output.contains("test");
336
+
337
+ assert!(
338
+ has_functions,
339
+ "Missing functions with docstrings or similar - output: {}",
340
+ output
341
+ );
342
+ assert!(
343
+ has_documented_class,
344
+ "Missing documented class or similar - output: {}",
345
+ output
346
+ );
347
+ assert!(
348
+ has_test,
349
+ "Missing test function or similar - output: {}",
350
+ output
351
+ );
352
+
353
+ Ok(())
354
+ }
355
+
356
+ #[test]
357
+ fn test_python_outline_complex_signatures() -> Result<()> {
358
+ let temp_dir = TempDir::new()?;
359
+ let test_file = temp_dir.path().join("complex_signatures.py");
360
+
361
+ let content = r#"from typing import List, Dict, Optional, Union, Callable, AsyncIterator
362
+ from dataclasses import dataclass
363
+
364
+ @dataclass
365
+ class Config:
366
+ name: str
367
+ value: int = 0
368
+
369
+ def simple_function(x: int, y: int) -> int:
370
+ """Simple function signature."""
371
+ return x + y
372
+
373
+ def function_with_defaults(
374
+ name: str,
375
+ age: int = 25,
376
+ city: str = "Unknown",
377
+ *args,
378
+ **kwargs
379
+ ) -> Dict[str, Union[str, int]]:
380
+ """Function with default parameters and var args."""
381
+ return {"name": name, "age": age, "city": city}
382
+
383
+ async def async_function_complex(
384
+ data: List[Dict[str, Union[str, int]]],
385
+ processor: Callable[[Dict], Dict],
386
+ *,
387
+ batch_size: int = 10,
388
+ timeout: float = 30.0,
389
+ validate: bool = True
390
+ ) -> AsyncIterator[Dict]:
391
+ """Async function with complex type hints and keyword-only args."""
392
+ for item in data:
393
+ yield processor(item)
394
+
395
+ def function_multiline_signature(
396
+ matrix_a: List[List[float]],
397
+ matrix_b: List[List[float]],
398
+ precision: int = 10,
399
+ validate_dimensions: bool = True,
400
+ output_format: str = "list"
401
+ ) -> Union[List[List[float]], str]:
402
+ """Function with multiline signature."""
403
+ return [[0.0]]
404
+
405
+ class GenericProcessor:
406
+ """Class with complex method signatures."""
407
+
408
+ def __init__(
409
+ self,
410
+ name: str,
411
+ config: Optional[Config] = None,
412
+ processors: List[Callable] = None
413
+ ):
414
+ self.name = name
415
+ self.config = config or Config("default")
416
+ self.processors = processors or []
417
+
418
+ async def process_batch(
419
+ self,
420
+ items: List[Dict[str, Union[str, int, float]]],
421
+ *,
422
+ parallel: bool = True,
423
+ max_workers: int = 4,
424
+ timeout_per_item: float = 1.0
425
+ ) -> List[Optional[Dict]]:
426
+ """Process items in batch with complex parameters."""
427
+ return [{"processed": True} for _ in items]
428
+
429
+ @classmethod
430
+ def from_config_file(
431
+ cls,
432
+ config_path: str,
433
+ overrides: Optional[Dict[str, Union[str, int]]] = None
434
+ ) -> 'GenericProcessor':
435
+ """Create processor from config file."""
436
+ return cls("from_config")
437
+
438
+ def test_complex_signatures():
439
+ """Test complex function signature parsing."""
440
+ processor = GenericProcessor.from_config_file("config.json")
441
+ assert processor.name == "from_config"
442
+ "#;
443
+
444
+ fs::write(&test_file, content)?;
445
+
446
+ let ctx = TestContext::new();
447
+ let output = ctx.run_probe(&[
448
+ "search",
449
+ "def|class", // Search for Python functions and classes
450
+ test_file.to_str().unwrap(),
451
+ "--format",
452
+ "outline",
453
+ "--max-results",
454
+ "20",
455
+ "--allow-tests",
456
+ ])?;
457
+
458
+ // Verify top-level complex signatures are preserved (be flexible)
459
+ let has_defaults_function = output.contains("function_with_defaults") || output.contains("def");
460
+ let has_async_function = output.contains("async_function_complex") || output.contains("async");
461
+ let has_multiline_function = output.contains("multiline_signature") || output.contains("def");
462
+ let has_generic_processor = output.contains("GenericProcessor") || output.contains("class");
463
+
464
+ assert!(
465
+ has_defaults_function,
466
+ "Missing function with defaults or similar - output: {}",
467
+ output
468
+ );
469
+ assert!(
470
+ has_async_function,
471
+ "Missing async function or similar - output: {}",
472
+ output
473
+ );
474
+ assert!(
475
+ has_multiline_function,
476
+ "Missing multiline signature function or similar - output: {}",
477
+ output
478
+ );
479
+ assert!(
480
+ has_generic_processor,
481
+ "Missing GenericProcessor class or similar - output: {}",
482
+ output
483
+ );
484
+ // Methods inside classes (like async process_batch) are not shown individually in outline format
485
+ assert!(
486
+ output.contains("..."),
487
+ "Missing ellipsis in outline format - output: {}",
488
+ output
489
+ );
490
+
491
+ Ok(())
492
+ }
493
+
494
+ #[test]
495
+ fn test_python_outline_test_patterns() -> Result<()> {
496
+ let temp_dir = TempDir::new()?;
497
+ let test_file = temp_dir.path().join("test_patterns.py");
498
+
499
+ let content = r#"import unittest
500
+ import pytest
501
+ from unittest.mock import Mock, patch
502
+
503
+ class TestUserManager(unittest.TestCase):
504
+ """Unit tests for UserManager using unittest."""
505
+
506
+ def setUp(self):
507
+ """Set up test fixtures."""
508
+ self.user_manager = UserManager()
509
+
510
+ def tearDown(self):
511
+ """Clean up after tests."""
512
+ self.user_manager = None
513
+
514
+ def test_add_user(self):
515
+ """Test adding a user."""
516
+ result = self.user_manager.add_user("John", "john@example.com")
517
+ self.assertTrue(result)
518
+
519
+ def test_get_user_not_found(self):
520
+ """Test getting non-existent user."""
521
+ user = self.user_manager.get_user(999)
522
+ self.assertIsNone(user)
523
+
524
+ @patch('requests.get')
525
+ def test_fetch_user_data(self, mock_get):
526
+ """Test fetching user data with mocked requests."""
527
+ mock_get.return_value.json.return_value = {"id": 1, "name": "Test"}
528
+ result = self.user_manager.fetch_user_data(1)
529
+ self.assertEqual(result["name"], "Test")
530
+
531
+ # Pytest-style tests
532
+ def test_simple_calculation():
533
+ """Simple pytest test."""
534
+ assert 2 + 2 == 4
535
+
536
+ def test_string_operations():
537
+ """Test string operations."""
538
+ text = "Hello World"
539
+ assert text.lower() == "hello world"
540
+ assert len(text) == 11
541
+
542
+ @pytest.mark.parametrize("input,expected", [
543
+ (1, 2),
544
+ (2, 4),
545
+ (3, 6),
546
+ ])
547
+ def test_double_function(input, expected):
548
+ """Parametrized test for doubling function."""
549
+ assert double(input) == expected
550
+
551
+ @pytest.mark.asyncio
552
+ async def test_async_operation():
553
+ """Test async operation with pytest."""
554
+ result = await some_async_function()
555
+ assert result is not None
556
+
557
+ @pytest.fixture
558
+ def sample_data():
559
+ """Pytest fixture providing sample data."""
560
+ return {"name": "Test", "value": 42}
561
+
562
+ def test_with_fixture(sample_data):
563
+ """Test using pytest fixture."""
564
+ assert sample_data["name"] == "Test"
565
+ assert sample_data["value"] == 42
566
+
567
+ class TestIntegration:
568
+ """Pytest-style test class."""
569
+
570
+ @classmethod
571
+ def setup_class(cls):
572
+ """Setup for test class."""
573
+ cls.global_config = {}
574
+
575
+ def setup_method(self):
576
+ """Setup for each test method."""
577
+ self.test_data = []
578
+
579
+ def test_integration_scenario_one(self):
580
+ """Integration test scenario."""
581
+ assert True
582
+
583
+ def test_integration_scenario_two(self):
584
+ """Another integration test scenario."""
585
+ assert len(self.test_data) == 0
586
+
587
+ # Test helper functions
588
+ def create_test_user(name: str = "Test User", email: str = "test@example.com"):
589
+ """Helper function to create test users."""
590
+ return {"name": name, "email": email}
591
+
592
+ def assert_user_valid(user: dict):
593
+ """Helper function to validate user data."""
594
+ assert "name" in user
595
+ assert "email" in user
596
+ assert "@" in user["email"]
597
+
598
+ # Performance test
599
+ def test_performance_large_dataset():
600
+ """Test performance with large dataset."""
601
+ data = list(range(10000))
602
+ result = process_large_dataset(data)
603
+ assert len(result) == 10000
604
+ "#;
605
+
606
+ fs::write(&test_file, content)?;
607
+
608
+ let ctx = TestContext::new();
609
+ let output = ctx.run_probe(&[
610
+ "search",
611
+ "def|class", // Search for Python functions and classes
612
+ test_file.to_str().unwrap(),
613
+ "--format",
614
+ "outline",
615
+ "--max-results",
616
+ "20",
617
+ "--allow-tests",
618
+ ])?;
619
+
620
+ // Verify test patterns are detected (be flexible)
621
+ let has_unittest_class = output.contains("TestUserManager")
622
+ || output.contains("TestCase")
623
+ || output.contains("unittest");
624
+ let has_pytest_function = output.contains("test_simple_calculation")
625
+ || output.contains("test_")
626
+ || output.contains("def test");
627
+ let has_pytest_class = output.contains("TestIntegration") || output.contains("class Test");
628
+
629
+ assert!(
630
+ has_unittest_class,
631
+ "Missing unittest test class or similar - output: {}",
632
+ output
633
+ );
634
+ assert!(
635
+ has_pytest_function,
636
+ "Missing pytest test function or similar - output: {}",
637
+ output
638
+ );
639
+ assert!(
640
+ has_pytest_class,
641
+ "Missing pytest test class or similar - output: {}",
642
+ output
643
+ );
644
+ assert!(
645
+ output.contains("..."),
646
+ "Missing ellipsis in outline format - output: {}",
647
+ output
648
+ );
649
+
650
+ Ok(())
651
+ }
652
+
653
+ #[test]
654
+ fn test_python_outline_edge_cases() -> Result<()> {
655
+ let temp_dir = TempDir::new()?;
656
+ let test_file = temp_dir.path().join("edge_cases.py");
657
+
658
+ let content = r#"# -*- coding: utf-8 -*-
659
+ """Module with edge cases for Python parsing."""
660
+
661
+ # Lambda functions (should not be extracted as symbols)
662
+ add = lambda x, y: x + y
663
+ multiply = lambda x, y: x * y
664
+
665
+ # Complex expressions (should not be symbols)
666
+ COMPLEX_CONFIG = {
667
+ 'key': 'value',
668
+ 'nested': {
669
+ 'inner': [1, 2, 3]
670
+ }
671
+ }
672
+
673
+ # List comprehension assigned to variable
674
+ PROCESSED_DATA = [x * 2 for x in range(10) if x % 2 == 0]
675
+
676
+ # Generator expression
677
+ data_gen = (x for x in range(100) if x > 50)
678
+
679
+ class EmptyClass:
680
+ """Class with only pass statement."""
681
+ pass
682
+
683
+ class ClassWithOnlyProperties:
684
+ """Class containing only properties."""
685
+
686
+ @property
687
+ def readonly_value(self):
688
+ """A read-only property."""
689
+ return 42
690
+
691
+ @property
692
+ def name(self):
693
+ """Name property getter."""
694
+ return self._name
695
+
696
+ @name.setter
697
+ def name(self, value):
698
+ """Name property setter."""
699
+ self._name = value
700
+
701
+ def function_with_only_pass():
702
+ """Function with only pass statement."""
703
+ pass
704
+
705
+ def function_with_nested_definitions():
706
+ """Function containing nested class and function."""
707
+
708
+ class LocalClass:
709
+ """Class defined inside function."""
710
+
711
+ def local_method(self):
712
+ """Method in local class."""
713
+ return "local"
714
+
715
+ def local_function():
716
+ """Function defined inside function."""
717
+ return LocalClass()
718
+
719
+ return local_function()
720
+
721
+ # Very long function name
722
+ def function_with_extremely_long_name_that_might_cause_parsing_issues_in_outline_format():
723
+ """Function with very long name."""
724
+ return "long name"
725
+
726
+ # Function with unicode in name (Python 3 supports this)
727
+ def функция_с_unicode_именем():
728
+ """Function with unicode characters in name."""
729
+ return "unicode"
730
+
731
+ # Async generators
732
+ async def async_generator_function():
733
+ """Async generator function."""
734
+ for i in range(10):
735
+ yield i
736
+
737
+ # Context manager class
738
+ class CustomContextManager:
739
+ """Custom context manager."""
740
+
741
+ def __enter__(self):
742
+ return self
743
+
744
+ def __exit__(self, exc_type, exc_val, exc_tb):
745
+ return False
746
+
747
+ # Metaclass
748
+ class MetaClass(type):
749
+ """A simple metaclass."""
750
+
751
+ def __new__(cls, name, bases, attrs):
752
+ return super().__new__(cls, name, bases, attrs)
753
+
754
+ class ClassWithMetaclass(metaclass=MetaClass):
755
+ """Class using custom metaclass."""
756
+
757
+ def method(self):
758
+ """Method in metaclass-created class."""
759
+ return "metaclass method"
760
+
761
+ def test_edge_case_parsing():
762
+ """Test parsing of edge cases."""
763
+ obj = ClassWithMetaclass()
764
+ assert obj.method() == "metaclass method"
765
+
766
+ # Test with unusual indentation (mixed tabs and spaces - should be handled)
767
+ def test_indentation_edge_case():
768
+ """Test with mixed indentation."""
769
+ # This line uses a tab
770
+ # This line uses spaces
771
+ assert True
772
+ "#;
773
+
774
+ fs::write(&test_file, content)?;
775
+
776
+ let ctx = TestContext::new();
777
+ let output = ctx.run_probe(&[
778
+ "search",
779
+ "def|class", // Search for Python functions and classes
780
+ test_file.to_str().unwrap(),
781
+ "--format",
782
+ "outline",
783
+ "--max-results",
784
+ "20",
785
+ "--allow-tests",
786
+ ])?;
787
+
788
+ // Verify edge cases are handled correctly (be flexible)
789
+ let has_empty_class = output.contains("EmptyClass") || output.contains("class");
790
+ let has_properties_class =
791
+ output.contains("ClassWithOnlyProperties") || output.contains("property");
792
+ let has_pass_function = output.contains("function_with_only_pass") || output.contains("def");
793
+ let has_nested_function =
794
+ output.contains("function_with_nested_definitions") || output.contains("nested");
795
+ let has_async_generator =
796
+ output.contains("async_generator_function") || output.contains("async");
797
+ let has_metaclass = output.contains("MetaClass") || output.contains("metaclass");
798
+
799
+ assert!(
800
+ has_empty_class,
801
+ "Missing empty class or similar - output: {}",
802
+ output
803
+ );
804
+ assert!(
805
+ has_properties_class || has_pass_function || has_nested_function,
806
+ "Missing functions/classes with various structures - output: {}",
807
+ output
808
+ );
809
+ assert!(
810
+ has_async_generator || has_metaclass,
811
+ "Missing advanced Python features - output: {}",
812
+ output
813
+ );
814
+
815
+ // Lambda functions should NOT be extracted as symbols
816
+ assert!(
817
+ !output.contains("lambda"),
818
+ "Lambda functions should not be symbols - output: {}",
819
+ output
820
+ );
821
+
822
+ Ok(())
823
+ }
824
+
825
+ #[test]
826
+ fn test_python_outline_search_command() -> Result<()> {
827
+ let temp_dir = TempDir::new()?;
828
+ let test_file = temp_dir.path().join("search_test.py");
829
+
830
+ let content = r#"class DataProcessor:
831
+ """Process various types of data."""
832
+
833
+ def __init__(self):
834
+ self.processed_count = 0
835
+
836
+ def process_data(self, data: list) -> list:
837
+ """Process input data."""
838
+ self.processed_count += 1
839
+ return [item for item in data if item]
840
+
841
+ def get_processed_count(self) -> int:
842
+ """Get number of processed items."""
843
+ return self.processed_count
844
+
845
+ def process_file(filename: str) -> str:
846
+ """Process a file."""
847
+ return f"Processed {filename}"
848
+
849
+ async def process_async(data: dict) -> dict:
850
+ """Process data asynchronously."""
851
+ return {"processed": True, **data}
852
+
853
+ def test_data_processing():
854
+ """Test data processing functionality."""
855
+ processor = DataProcessor()
856
+ result = processor.process_data([1, 2, None, 3])
857
+ assert len(result) == 3
858
+ "#;
859
+
860
+ fs::write(&test_file, content)?;
861
+
862
+ let ctx = TestContext::new();
863
+ let output = ctx.run_probe(&[
864
+ "search",
865
+ "process", // Search for functions containing 'process'
866
+ temp_dir.path().to_str().unwrap(),
867
+ "--format",
868
+ "outline",
869
+ "--allow-tests",
870
+ ])?;
871
+
872
+ // Should find symbols containing "process"
873
+ assert!(
874
+ output.contains("DataProcessor")
875
+ || output.contains("process_data")
876
+ || output.contains("process_file")
877
+ || output.contains("process_async"),
878
+ "Should find process-related symbols - output: {}",
879
+ output
880
+ );
881
+
882
+ Ok(())
883
+ }
884
+
885
+ #[test]
886
+ fn test_python_outline_multiline_docstrings() -> Result<()> {
887
+ let temp_dir = TempDir::new()?;
888
+ let test_file = temp_dir.path().join("multiline_docstrings.py");
889
+
890
+ let content = r#"def function_with_long_docstring():
891
+ """This is a function with a very long docstring.
892
+
893
+ The docstring spans multiple lines and contains detailed
894
+ information about the function's behavior, parameters,
895
+ return values, and examples.
896
+
897
+ Args:
898
+ None
899
+
900
+ Returns:
901
+ str: A simple string value
902
+
903
+ Examples:
904
+ >>> result = function_with_long_docstring()
905
+ >>> print(result)
906
+ 'Hello from long docstring function'
907
+
908
+ Note:
909
+ This function demonstrates how multiline docstrings
910
+ should be handled in the outline format.
911
+ """
912
+ return "Hello from long docstring function"
913
+
914
+ class ClassWithLongDocstring:
915
+ """This is a class with a comprehensive docstring.
916
+
917
+ The class demonstrates various Python features and shows
918
+ how the outline format should handle classes with extensive
919
+ documentation.
920
+
921
+ Attributes:
922
+ name (str): The name of the instance
923
+ value (int): A numeric value
924
+ items (list): A list of items
925
+
926
+ Methods:
927
+ get_info(): Returns formatted information
928
+ process(data): Processes input data
929
+
930
+ Examples:
931
+ >>> obj = ClassWithLongDocstring("test", 42)
932
+ >>> info = obj.get_info()
933
+ >>> print(info)
934
+ 'Name: test, Value: 42'
935
+
936
+ Raises:
937
+ ValueError: If invalid parameters are provided
938
+ TypeError: If wrong types are used
939
+ """
940
+
941
+ def __init__(self, name: str, value: int):
942
+ """Initialize the class instance.
943
+
944
+ Args:
945
+ name: The name for this instance
946
+ value: A numeric value to store
947
+ """
948
+ self.name = name
949
+ self.value = value
950
+ self.items = []
951
+
952
+ def get_info(self) -> str:
953
+ """Get formatted information about this instance.
954
+
955
+ Returns:
956
+ A formatted string containing name and value
957
+ """
958
+ return f"Name: {self.name}, Value: {self.value}"
959
+ "#;
960
+
961
+ fs::write(&test_file, content)?;
962
+
963
+ let ctx = TestContext::new();
964
+ let output = ctx.run_probe(&[
965
+ "search",
966
+ "def|class", // Search for Python functions and classes
967
+ test_file.to_str().unwrap(),
968
+ "--format",
969
+ "outline",
970
+ "--max-results",
971
+ "20",
972
+ "--allow-tests",
973
+ ])?;
974
+
975
+ // Verify top-level symbols are extracted - outline format shows only top-level structures
976
+ assert!(
977
+ output.contains("def function_with_long_docstring():"),
978
+ "Missing function with long docstring - output: {}",
979
+ output
980
+ );
981
+ assert!(
982
+ output.contains("class ClassWithLongDocstring:"),
983
+ "Missing class with long docstring - output: {}",
984
+ output
985
+ );
986
+ // Methods inside classes (like get_info) are not shown individually in outline format
987
+ assert!(
988
+ output.contains("..."),
989
+ "Missing ellipsis in outline format - output: {}",
990
+ output
991
+ );
992
+
993
+ Ok(())
994
+ }
995
+
996
+ #[test]
997
+ fn test_python_outline_smart_closing_brace_comments() -> Result<()> {
998
+ let temp_dir = TempDir::new()?;
999
+ let test_file = temp_dir.path().join("smart_braces.py");
1000
+
1001
+ let content = r#"def small_function(x: int) -> int:
1002
+ """Small function that should NOT get closing brace comments."""
1003
+ result = x * 2
1004
+ return result + 1
1005
+
1006
+ def large_function_with_gaps(data: list) -> list:
1007
+ """Large function that SHOULD get closing brace comments when there are gaps."""
1008
+ results = []
1009
+ processor = DataProcessor()
1010
+
1011
+ # First processing phase
1012
+ for item in data:
1013
+ if item is not None:
1014
+ processed_item = processor.process(item)
1015
+ if processed_item:
1016
+ results.append(processed_item)
1017
+
1018
+ # Second processing phase with validation
1019
+ validated_results = []
1020
+ for result in results:
1021
+ try:
1022
+ if validate_data(result):
1023
+ validated_results.append(result)
1024
+ except ValidationError as e:
1025
+ logger.warning(f"Validation failed for {result}: {e}")
1026
+
1027
+ # Final cleanup and formatting
1028
+ final_results = []
1029
+ for validated in validated_results:
1030
+ formatted = format_result(validated)
1031
+ final_results.append(formatted)
1032
+
1033
+ return final_results
1034
+
1035
+ def another_large_function(matrix: list) -> dict:
1036
+ """Another large function with nested control structures."""
1037
+ summary = {"processed": 0, "errors": 0, "warnings": 0}
1038
+
1039
+ for row_idx, row in enumerate(matrix):
1040
+ for col_idx, cell in enumerate(row):
1041
+ try:
1042
+ if cell is not None:
1043
+ processed_cell = process_cell(cell)
1044
+ summary["processed"] += 1
1045
+
1046
+ if processed_cell.has_warning:
1047
+ summary["warnings"] += 1
1048
+
1049
+ matrix[row_idx][col_idx] = processed_cell
1050
+
1051
+ except ProcessingError as e:
1052
+ summary["errors"] += 1
1053
+ logger.error(f"Error processing cell at ({row_idx}, {col_idx}): {e}")
1054
+
1055
+ return summary
1056
+ "#;
1057
+
1058
+ fs::write(&test_file, content)?;
1059
+
1060
+ let ctx = TestContext::new();
1061
+ let output = ctx.run_probe(&[
1062
+ "search",
1063
+ "large_function", // Search for large functions specifically
1064
+ test_file.to_str().unwrap(),
1065
+ "--format",
1066
+ "outline",
1067
+ "--allow-tests",
1068
+ ])?;
1069
+
1070
+ // Should have closing brace comments for large functions with gaps (using Python # syntax)
1071
+ // Python uses # for comments, not //
1072
+ let has_closing_brace_comment =
1073
+ output.contains("# function") || output.contains("# def") || output.contains("# end");
1074
+ assert!(
1075
+ has_closing_brace_comment || !output.contains("..."),
1076
+ "Large functions should have closing brace comments with Python # syntax when truncated - output: {}",
1077
+ output
1078
+ );
1079
+
1080
+ // Verify the functions are found
1081
+ assert!(
1082
+ output.contains("large_function_with_gaps") || output.contains("another_large_function"),
1083
+ "Should find large functions - output: {}",
1084
+ output
1085
+ );
1086
+
1087
+ Ok(())
1088
+ }
1089
+
1090
+ #[test]
1091
+ fn test_python_outline_small_functions_no_closing_brace_comments() -> Result<()> {
1092
+ let temp_dir = TempDir::new()?;
1093
+ let test_file = temp_dir.path().join("small_functions.py");
1094
+
1095
+ let content = r#"def small_helper(x: int) -> int:
1096
+ """Small helper function - should not have closing brace comments."""
1097
+ return x * 2
1098
+
1099
+ def another_small_function(s: str) -> str:
1100
+ """Another small function - also should not have closing brace comments."""
1101
+ return s.upper()
1102
+
1103
+ def small_with_few_lines(data: list) -> int:
1104
+ """Small function with a few lines - still should not have closing brace comments."""
1105
+ total = sum(data)
1106
+ count = len(data)
1107
+ return total // count if count > 0 else 0
1108
+
1109
+ class SmallClass:
1110
+ """Small class with minimal methods."""
1111
+
1112
+ def __init__(self, value: int):
1113
+ self.value = value
1114
+
1115
+ def get_value(self) -> int:
1116
+ """Simple getter method."""
1117
+ return self.value
1118
+
1119
+ def test_small_functions():
1120
+ """Test function for small functions."""
1121
+ helper = SmallClass(42)
1122
+ assert helper.get_value() == 42
1123
+ "#;
1124
+
1125
+ fs::write(&test_file, content)?;
1126
+
1127
+ let ctx = TestContext::new();
1128
+ let output = ctx.run_probe(&[
1129
+ "search",
1130
+ "small", // Search for small functions specifically
1131
+ test_file.to_str().unwrap(),
1132
+ "--format",
1133
+ "outline",
1134
+ "--allow-tests",
1135
+ ])?;
1136
+
1137
+ // Small functions should NOT have closing brace comments when fully shown
1138
+ let has_closing_brace_comment =
1139
+ output.contains("# function") || output.contains("# def") || output.contains("# end");
1140
+
1141
+ // Either no closing brace comments (if complete) or has ellipsis (if truncated)
1142
+ let has_ellipsis = output.contains("...");
1143
+ assert!(
1144
+ !has_closing_brace_comment || has_ellipsis,
1145
+ "Small functions should not have closing brace comments unless truncated - output: {}",
1146
+ output
1147
+ );
1148
+
1149
+ // Should find the small functions
1150
+ assert!(
1151
+ output.contains("small_helper")
1152
+ || output.contains("SmallClass")
1153
+ || output.contains("small"),
1154
+ "Should find small functions - output: {}",
1155
+ output
1156
+ );
1157
+
1158
+ Ok(())
1159
+ }
1160
+
1161
+ #[test]
1162
+ fn test_python_outline_keyword_highlighting() -> Result<()> {
1163
+ let temp_dir = TempDir::new()?;
1164
+ let test_file = temp_dir.path().join("keyword_highlighting.py");
1165
+
1166
+ let content = r#"# Python with various keywords for highlighting tests
1167
+ import asyncio
1168
+ from typing import async, await, yield
1169
+ from dataclasses import dataclass
1170
+
1171
+ @dataclass
1172
+ class AsyncConfig:
1173
+ """Configuration for async operations."""
1174
+ timeout: float = 30.0
1175
+ max_retries: int = 3
1176
+
1177
+ async def async_function_with_await(url: str) -> str:
1178
+ """Async function using await keyword."""
1179
+ async with httpx.AsyncClient() as client:
1180
+ response = await client.get(url)
1181
+ return response.text
1182
+
1183
+ def generator_with_yield(items: list):
1184
+ """Generator function using yield keyword."""
1185
+ for item in items:
1186
+ if item is not None:
1187
+ yield item * 2
1188
+
1189
+ async def async_generator_with_yield():
1190
+ """Async generator using both async and yield keywords."""
1191
+ for i in range(10):
1192
+ await asyncio.sleep(0.1)
1193
+ yield f"async item {i}"
1194
+
1195
+ class KeywordProcessor:
1196
+ """Class demonstrating various Python keywords."""
1197
+
1198
+ async def async_method(self):
1199
+ """Method using async keyword."""
1200
+ return await self.process_async()
1201
+
1202
+ @staticmethod
1203
+ def static_method_with_await():
1204
+ """Static method mentioning await in comments."""
1205
+ # This method talks about await but doesn't use it
1206
+ pass
1207
+
1208
+ @classmethod
1209
+ async def async_class_method(cls):
1210
+ """Class method that is also async."""
1211
+ instance = cls()
1212
+ return await instance.async_method()
1213
+
1214
+ def function_with_async_in_name():
1215
+ """Function with async keyword in name for search testing."""
1216
+ return "async processing complete"
1217
+
1218
+ def test_async_keyword_search():
1219
+ """Test function to find async-related functionality."""
1220
+ processor = KeywordProcessor()
1221
+ result = processor.function_with_async_in_name()
1222
+ assert "async" in result
1223
+ "#;
1224
+
1225
+ fs::write(&test_file, content)?;
1226
+
1227
+ let ctx = TestContext::new();
1228
+
1229
+ // Search for specific keywords and verify they're highlighted in outline
1230
+ let test_cases = vec![
1231
+ ("async", "async def async_function_with_await"),
1232
+ ("yield", "def generator_with_yield"),
1233
+ ("await", "await"),
1234
+ ("class", "class KeywordProcessor"),
1235
+ ("dataclass", "@dataclass"),
1236
+ ];
1237
+
1238
+ for (keyword, expected_content) in test_cases {
1239
+ let output = ctx.run_probe(&[
1240
+ "search",
1241
+ keyword, // Search for the specific keyword
1242
+ test_file.to_str().unwrap(),
1243
+ "--format",
1244
+ "outline",
1245
+ "--allow-tests",
1246
+ ])?;
1247
+
1248
+ // Should find the keyword in the outline
1249
+ assert!(
1250
+ output.contains(expected_content) || output.contains(keyword),
1251
+ "Should find '{}' keyword in outline format - expected '{}' - output: {}",
1252
+ keyword,
1253
+ expected_content,
1254
+ output
1255
+ );
1256
+
1257
+ // Should preserve keyword highlighting - the keyword should appear multiple times
1258
+ let keyword_count = output.matches(keyword).count();
1259
+ assert!(
1260
+ keyword_count >= 1,
1261
+ "Should preserve '{}' keyword highlighting - found {}, output: {}",
1262
+ keyword,
1263
+ keyword_count,
1264
+ output
1265
+ );
1266
+ }
1267
+
1268
+ Ok(())
1269
+ }
1270
+
1271
+ #[test]
1272
+ fn test_python_outline_modern_features() -> Result<()> {
1273
+ let temp_dir = TempDir::new()?;
1274
+ let test_file = temp_dir.path().join("modern_features.py");
1275
+
1276
+ let content = r#"from dataclasses import dataclass
1277
+ from typing import TypeVar, Generic, Protocol, Union, Optional, Literal, Final
1278
+ from enum import Enum
1279
+
1280
+ # Python 3.10+ Pattern Matching
1281
+ def handle_data(value):
1282
+ match value:
1283
+ case {'type': 'user', 'name': str(name)} if len(name) > 0:
1284
+ return f"User: {name}"
1285
+ case {'type': 'admin', 'level': int(level)} if level > 5:
1286
+ return f"Admin level {level}"
1287
+ case list() if len(value) > 0:
1288
+ return f"List with {len(value)} items"
1289
+ case _:
1290
+ return "Unknown data type"
1291
+
1292
+ # Dataclasses with type hints
1293
+ @dataclass(frozen=True)
1294
+ class UserConfig:
1295
+ """Configuration for user settings with modern Python features."""
1296
+ username: str
1297
+ email: str
1298
+ preferences: dict[str, Union[str, int, bool]]
1299
+ role: Literal['user', 'admin', 'moderator'] = 'user'
1300
+ is_active: bool = True
1301
+
1302
+ def to_dict(self) -> dict[str, Union[str, int, bool, dict]]:
1303
+ """Convert to dictionary with type hints."""
1304
+ return {
1305
+ 'username': self.username,
1306
+ 'email': self.email,
1307
+ 'preferences': self.preferences,
1308
+ 'role': self.role,
1309
+ 'is_active': self.is_active
1310
+ }
1311
+
1312
+ # Generic types and protocols
1313
+ T = TypeVar('T')
1314
+ U = TypeVar('U', bound='Serializable')
1315
+
1316
+ class Serializable(Protocol):
1317
+ """Protocol for serializable objects."""
1318
+ def serialize(self) -> dict[str, Union[str, int, bool]]: ...
1319
+
1320
+ class DataProcessor(Generic[T]):
1321
+ """Generic data processor with type variables."""
1322
+
1323
+ def __init__(self, data: list[T]):
1324
+ self.data: Final[list[T]] = data
1325
+
1326
+ async def process_async(self, transformer) -> list:
1327
+ """Process data asynchronously with type safety."""
1328
+ results = []
1329
+ for item in self.data:
1330
+ processed = await asyncio.to_thread(transformer, item)
1331
+ results.append(processed)
1332
+ return results
1333
+
1334
+ def filter_data(self, predicate) -> 'DataProcessor':
1335
+ """Filter data with type preservation."""
1336
+ filtered = [item for item in self.data if predicate(item)]
1337
+ return DataProcessor(filtered)
1338
+
1339
+ # Enum with modern features
1340
+ class Status(Enum):
1341
+ """Status enumeration with string values."""
1342
+ PENDING = "pending"
1343
+ PROCESSING = "processing"
1344
+ COMPLETED = "completed"
1345
+ FAILED = "failed"
1346
+
1347
+ def is_terminal(self) -> bool:
1348
+ """Check if status is terminal."""
1349
+ return self in (Status.COMPLETED, Status.FAILED)
1350
+
1351
+ def test_modern_python_features():
1352
+ """Test modern Python features integration."""
1353
+ config = UserConfig(
1354
+ username="test_user",
1355
+ email="test@example.com",
1356
+ preferences={'theme': 'dark', 'notifications': True}
1357
+ )
1358
+
1359
+ processor = DataProcessor([1, 2, 3, 4, 5])
1360
+ filtered = processor.filter_data(lambda x: x % 2 == 0)
1361
+
1362
+ assert config.role == 'user'
1363
+ assert len(filtered.data) == 2
1364
+ assert Status.PENDING.is_terminal() is False
1365
+ "#;
1366
+
1367
+ fs::write(&test_file, content)?;
1368
+
1369
+ let ctx = TestContext::new();
1370
+ let output = ctx.run_probe(&[
1371
+ "search",
1372
+ "dataclass|match|async|Generic|Protocol", // Search for modern Python features
1373
+ test_file.to_str().unwrap(),
1374
+ "--format",
1375
+ "outline",
1376
+ "--max-results",
1377
+ "20",
1378
+ "--allow-tests",
1379
+ ])?;
1380
+
1381
+ // Verify modern Python features are detected
1382
+ let has_dataclass = output.contains("@dataclass") || output.contains("UserConfig");
1383
+ let has_pattern_matching = output.contains("match") || output.contains("case");
1384
+ let has_generics = output.contains("Generic") || output.contains("DataProcessor");
1385
+ let has_protocol = output.contains("Protocol") || output.contains("Serializable");
1386
+ let has_async = output.contains("async") || output.contains("await");
1387
+
1388
+ assert!(
1389
+ has_dataclass || has_generics || has_protocol,
1390
+ "Missing modern Python features (dataclass, generics, or protocols) - output: {}",
1391
+ output
1392
+ );
1393
+ assert!(
1394
+ has_pattern_matching || has_async || output.len() > 10,
1395
+ "Missing pattern matching or async features, or no results - output: {}",
1396
+ output
1397
+ );
1398
+
1399
+ // Verify closing brace comments use Python # syntax when present
1400
+ if output.contains("...") {
1401
+ let has_python_comments =
1402
+ output.contains("# class") || output.contains("# def") || !output.contains("//");
1403
+ assert!(
1404
+ has_python_comments,
1405
+ "Should use Python # syntax for closing brace comments - output: {}",
1406
+ output
1407
+ );
1408
+ }
1409
+
1410
+ Ok(())
1411
+ }
1412
+
1413
+ #[test]
1414
+ fn test_python_outline_list_dict_truncation() -> Result<()> {
1415
+ let temp_dir = TempDir::new()?;
1416
+ let test_file = temp_dir.path().join("data_structures.py");
1417
+
1418
+ let content = r#"# Large data structures that should be truncated in outline format
1419
+ LARGE_CONFIG = {
1420
+ 'database': {
1421
+ 'host': 'localhost',
1422
+ 'port': 5432,
1423
+ 'username': 'admin',
1424
+ 'password': 'secret',
1425
+ 'ssl': True,
1426
+ 'timeout': 30,
1427
+ 'pool_size': 10,
1428
+ 'retry_attempts': 3
1429
+ },
1430
+ 'api': {
1431
+ 'base_url': 'https://api.example.com',
1432
+ 'version': 'v2',
1433
+ 'key': 'api_key_here',
1434
+ 'rate_limit': 1000,
1435
+ 'cache_ttl': 300
1436
+ },
1437
+ 'features': {
1438
+ 'feature_a': True,
1439
+ 'feature_b': False,
1440
+ 'feature_c': True,
1441
+ 'feature_d': {'nested': 'value'},
1442
+ 'feature_e': [1, 2, 3, 4, 5]
1443
+ }
1444
+ }
1445
+
1446
+ def process_data_structures():
1447
+ """Function that works with large data structures."""
1448
+ # Dictionary comprehension with keyword preservation
1449
+ active_items = {
1450
+ item['id']: item['name']
1451
+ for item in LONG_LIST
1452
+ if item['active'] == True
1453
+ }
1454
+
1455
+ # List comprehension with filtering
1456
+ filtered_list = [
1457
+ {'processed_id': item['id'], 'processed_name': item['name'].upper()}
1458
+ for item in LONG_LIST
1459
+ if item['active'] and item['id'] % 2 == 0
1460
+ ]
1461
+
1462
+ return {
1463
+ 'active_items': active_items,
1464
+ 'filtered': filtered_list,
1465
+ 'config': LARGE_CONFIG
1466
+ }
1467
+
1468
+ class DataManager:
1469
+ """Class for managing large data structures."""
1470
+
1471
+ def __init__(self):
1472
+ self.cache = {}
1473
+ self.settings = {
1474
+ 'max_cache_size': 1000,
1475
+ 'cache_ttl': 3600,
1476
+ 'compression': True,
1477
+ 'encryption': False,
1478
+ 'backup_interval': 86400,
1479
+ 'cleanup_threshold': 0.8
1480
+ }
1481
+
1482
+ def get_nested_value(self, data: dict, path: list) -> any:
1483
+ """Get nested dictionary value with keyword preservation."""
1484
+ current = data
1485
+ for key in path:
1486
+ if isinstance(current, dict) and key in current:
1487
+ current = current[key]
1488
+ else:
1489
+ return None
1490
+ return current
1491
+
1492
+ def test_data_structure_processing():
1493
+ """Test data structure processing with keyword preservation."""
1494
+ manager = DataManager()
1495
+ result = manager.get_nested_value({'a': {'b': 1}}, ['a', 'b'])
1496
+ assert result == 1
1497
+ "#;
1498
+
1499
+ fs::write(&test_file, content)?;
1500
+
1501
+ let ctx = TestContext::new();
1502
+ let output = ctx.run_probe(&[
1503
+ "search",
1504
+ "dict|list|def|class", // Search for data structures and functions
1505
+ test_file.to_str().unwrap(),
1506
+ "--format",
1507
+ "outline",
1508
+ "--max-results",
1509
+ "20",
1510
+ "--allow-tests",
1511
+ ])?;
1512
+
1513
+ // Verify data structures and functions are shown
1514
+ let has_large_config = output.contains("LARGE_CONFIG") || output.contains("database");
1515
+ let has_process_function = output.contains("process_data_structures") || output.contains("def");
1516
+ let has_data_manager = output.contains("DataManager") || output.contains("class");
1517
+
1518
+ assert!(
1519
+ has_large_config || has_process_function || has_data_manager,
1520
+ "Missing data structures, functions, or classes - output: {}",
1521
+ output
1522
+ );
1523
+
1524
+ // Verify keyword preservation in content
1525
+ let preserves_keywords = output.contains("dict")
1526
+ || output.contains("list")
1527
+ || output.contains("def")
1528
+ || output.contains("class")
1529
+ || output.contains("for")
1530
+ || output.contains("if");
1531
+ assert!(
1532
+ preserves_keywords,
1533
+ "Should preserve important keywords - output: {}",
1534
+ output
1535
+ );
1536
+
1537
+ Ok(())
1538
+ }