descry-codegraph 0.3.2__tar.gz → 0.3.3__tar.gz

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 (134) hide show
  1. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/CHANGELOG.md +13 -0
  2. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/CLAUDE.md +1 -1
  3. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/PKG-INFO +3 -3
  4. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/README.md +2 -2
  5. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/pyproject.toml +1 -1
  6. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/__init__.py +1 -1
  7. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/generate.py +19 -3
  8. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/handlers.py +2 -2
  9. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_generate.py +48 -0
  10. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/.github/assets/01-landing.png +0 -0
  11. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/.github/workflows/ci.yml +0 -0
  12. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/.github/workflows/release.yml +0 -0
  13. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/.gitignore +0 -0
  14. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/LICENSE +0 -0
  15. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/SECURITY.md +0 -0
  16. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/THIRD-PARTY-NOTICES.md +0 -0
  17. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/claude-skill/README.md +0 -0
  18. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/claude-skill/descry/SKILL.md +0 -0
  19. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/claude-skill/descry/references/cli-reference.md +0 -0
  20. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/claude-skill/descry/references/mcp-tools.md +0 -0
  21. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/claude-skill/descry/references/recipes.md +0 -0
  22. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/justfile +0 -0
  23. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/pi-extension/README.md +0 -0
  24. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/pi-extension/descry-cli.py +0 -0
  25. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/pi-extension/descry-tools.ts +0 -0
  26. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/_comments.py +0 -0
  27. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/_env.py +0 -0
  28. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/_files.py +0 -0
  29. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/_graph.py +0 -0
  30. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/_stdlib.py +0 -0
  31. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/clang_parser.py +0 -0
  32. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/cli.py +0 -0
  33. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/cross_lang.py +0 -0
  34. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/dart_parser.py +0 -0
  35. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/dotnet_parser.py +0 -0
  36. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/embeddings.py +0 -0
  37. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/git_history.py +0 -0
  38. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/go_parser.py +0 -0
  39. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/java_parser.py +0 -0
  40. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/mcp_server.py +0 -0
  41. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/php_parser.py +0 -0
  42. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/query.py +0 -0
  43. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/ruby_parser.py +0 -0
  44. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/__init__.py +0 -0
  45. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/adapter.py +0 -0
  46. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/adapters/__init__.py +0 -0
  47. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/adapters/_empty_environment.json +0 -0
  48. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/adapters/_java_compat.init.gradle +0 -0
  49. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/adapters/clang.py +0 -0
  50. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/adapters/dart.py +0 -0
  51. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/adapters/dotnet.py +0 -0
  52. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/adapters/go.py +0 -0
  53. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/adapters/java.py +0 -0
  54. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/adapters/php.py +0 -0
  55. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/adapters/python.py +0 -0
  56. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/adapters/ruby.py +0 -0
  57. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/adapters/rust.py +0 -0
  58. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/adapters/typescript.py +0 -0
  59. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/cache.py +0 -0
  60. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/parser.py +0 -0
  61. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/pb2.py +0 -0
  62. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/scip/support.py +0 -0
  63. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/stdlib/c.json +0 -0
  64. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/stdlib/cpp.json +0 -0
  65. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/stdlib/dart.json +0 -0
  66. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/stdlib/dotnet.json +0 -0
  67. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/stdlib/go.json +0 -0
  68. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/stdlib/java.json +0 -0
  69. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/stdlib/node.json +0 -0
  70. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/stdlib/php.json +0 -0
  71. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/stdlib/python.json +0 -0
  72. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/stdlib/ruby.json +0 -0
  73. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/stdlib/rust.json +0 -0
  74. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/stdlib/typescript.json +0 -0
  75. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/web/__init__.py +0 -0
  76. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/web/server.py +0 -0
  77. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/web/web/index.html +0 -0
  78. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/src/descry/web/web/style.css +0 -0
  79. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/__init__.py +0 -0
  80. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/conftest.py +0 -0
  81. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/eval/README.md +0 -0
  82. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/eval/__init__.py +0 -0
  83. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/eval/compare.py +0 -0
  84. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/eval/corpus.py +0 -0
  85. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/eval/metrics.py +0 -0
  86. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/eval/registry.py +0 -0
  87. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/eval/results/results-descry.json +0 -0
  88. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/eval/results/results-ripgrep.json +0 -0
  89. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/fixtures/small_graph.json +0 -0
  90. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_backtracking.py +0 -0
  91. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_clang_parser.py +0 -0
  92. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_cli.py +0 -0
  93. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_config.py +0 -0
  94. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_cross_lang.py +0 -0
  95. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_dart_parser.py +0 -0
  96. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_dotnet_parser.py +0 -0
  97. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_embeddings.py +0 -0
  98. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_git_history.py +0 -0
  99. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_go_parser.py +0 -0
  100. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_handlers.py +0 -0
  101. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_hardening.py +0 -0
  102. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_interfaces.py +0 -0
  103. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_java_parser.py +0 -0
  104. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_mcp.py +0 -0
  105. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_non_regular_files.py +0 -0
  106. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_php_parser.py +0 -0
  107. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_query.py +0 -0
  108. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_ruby_parser.py +0 -0
  109. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_scip.py +0 -0
  110. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_scip_cache.py +0 -0
  111. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_scip_clang.py +0 -0
  112. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_scip_dart.py +0 -0
  113. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_scip_dotnet.py +0 -0
  114. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_scip_go.py +0 -0
  115. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_scip_java.py +0 -0
  116. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_scip_php.py +0 -0
  117. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_scip_ruby.py +0 -0
  118. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_stdlib.py +0 -0
  119. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_web_server.py +0 -0
  120. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tests/test_written_through.py +0 -0
  121. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tools/stdlib/README.md +0 -0
  122. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tools/stdlib/common.py +0 -0
  123. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tools/stdlib/gen_c.py +0 -0
  124. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tools/stdlib/gen_cpp.py +0 -0
  125. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tools/stdlib/gen_dart.py +0 -0
  126. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tools/stdlib/gen_dotnet.py +0 -0
  127. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tools/stdlib/gen_go.py +0 -0
  128. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tools/stdlib/gen_java.py +0 -0
  129. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tools/stdlib/gen_node.py +0 -0
  130. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tools/stdlib/gen_php.py +0 -0
  131. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tools/stdlib/gen_python.py +0 -0
  132. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tools/stdlib/gen_ruby.py +0 -0
  133. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tools/stdlib/gen_rust.py +0 -0
  134. {descry_codegraph-0.3.2 → descry_codegraph-0.3.3}/tools/stdlib/gen_typescript.py +0 -0
@@ -6,6 +6,19 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.3.3] — 2026-10-23
10
+
11
+ ### Fixed
12
+
13
+ - A `bin` directory is indexed: Dart keeps its entry points there and Rust
14
+ its extra binaries (`src/bin/`). Only the `bin` of a .NET project or of
15
+ an Eclipse project, beside its project file or `.classpath`, is left out
16
+ as build output; every `bin` was.
17
+ - A Dart call of a standard type's name without `new`, `StringBuffer()`,
18
+ makes an instance of that type, as `new StringBuffer()` does. Calls on it
19
+ were taken as calls on an unknown receiver and listed as possible calls
20
+ of every project method of their name (`toString`, `write`, `close`).
21
+
9
22
  ## [0.3.2] — 2026-10-23
10
23
 
11
24
  ### Fixed
@@ -23,7 +23,7 @@ just test tests/test_handlers.py::test_index # one test
23
23
  just test -k "cross_lang and not slow" # by expression
24
24
  ```
25
25
 
26
- Python 3.11+ required (enforced by `pyproject.toml`). Pre-commit gate: `just lint && just fmt && just test` all pass (2810 tests currently — a drop is a regression signal).
26
+ Python 3.11+ required (enforced by `pyproject.toml`). Pre-commit gate: `just lint && just fmt && just test` all pass (2812 tests currently — a drop is a regression signal).
27
27
 
28
28
  Invoke the tool while developing:
29
29
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: descry-codegraph
3
- Version: 0.3.2
3
+ Version: 0.3.3
4
4
  Summary: Codebase knowledge graph: polyglot indexer, semantic search, call-graph analysis
5
5
  Project-URL: Homepage, https://github.com/06chaynes/descry
6
6
  Project-URL: Repository, https://github.com/06chaynes/descry
@@ -267,7 +267,7 @@ For customization, add a `.descry.toml` to your project root.
267
267
 
268
268
  ```toml
269
269
  [project]
270
- # OPTIONAL — REPLACES the 25-element default. Leave unset to keep defaults
270
+ # OPTIONAL — REPLACES the 24-element default. Leave unset to keep defaults
271
271
  # (.git, .gradle, .next, .svelte-kit, .venv, node_modules, target, build, …).
272
272
  # excluded_dirs = ["target", "node_modules", "dist", "build", "vendor"]
273
273
  # OPTIONAL — in a git repository, files git ignores are not indexed.
@@ -393,7 +393,7 @@ Share of project calls resolved without SCIP, measured on public repositories at
393
393
  | C# | serilog `bebc771`, Newtonsoft.Json `52fa3ae` (`Src/Newtonsoft.Json`) | 94%, 91% |
394
394
  | C | jq `a19efdd`, libuv `954c1d1` | 99%, 79% |
395
395
  | C++ | leveldb `7ee830d`, fmt `c4927e6` | 97%, 86% |
396
- | Dart | shelf `b2cb503`, riverpod `1efba1c` (`packages/riverpod`) | 93%, 91% |
396
+ | Dart | shelf `b2cb503`, riverpod `1efba1c` (`packages/riverpod`) | 95%, 91% |
397
397
  | Ruby | rack `a9833c8`, sinatra `cb22afd` | 70%, 39% |
398
398
 
399
399
  The remainder is unresolved, not wrong: of 450 resolved edges drawn at random from these repositories and read against the source, every one reaches the definition the call reaches. Ruby is low because the language declares no types and calls inside DSL blocks run with another `self`; libuv because most of its functions exist once for Unix and once for Windows, and the build files, not the source, choose between them.
@@ -202,7 +202,7 @@ For customization, add a `.descry.toml` to your project root.
202
202
 
203
203
  ```toml
204
204
  [project]
205
- # OPTIONAL — REPLACES the 25-element default. Leave unset to keep defaults
205
+ # OPTIONAL — REPLACES the 24-element default. Leave unset to keep defaults
206
206
  # (.git, .gradle, .next, .svelte-kit, .venv, node_modules, target, build, …).
207
207
  # excluded_dirs = ["target", "node_modules", "dist", "build", "vendor"]
208
208
  # OPTIONAL — in a git repository, files git ignores are not indexed.
@@ -328,7 +328,7 @@ Share of project calls resolved without SCIP, measured on public repositories at
328
328
  | C# | serilog `bebc771`, Newtonsoft.Json `52fa3ae` (`Src/Newtonsoft.Json`) | 94%, 91% |
329
329
  | C | jq `a19efdd`, libuv `954c1d1` | 99%, 79% |
330
330
  | C++ | leveldb `7ee830d`, fmt `c4927e6` | 97%, 86% |
331
- | Dart | shelf `b2cb503`, riverpod `1efba1c` (`packages/riverpod`) | 93%, 91% |
331
+ | Dart | shelf `b2cb503`, riverpod `1efba1c` (`packages/riverpod`) | 95%, 91% |
332
332
  | Ruby | rack `a9833c8`, sinatra `cb22afd` | 70%, 39% |
333
333
 
334
334
  The remainder is unresolved, not wrong: of 450 resolved edges drawn at random from these repositories and read against the source, every one reaches the definition the call reaches. Ruby is low because the language declares no types and calls inside DSL blocks run with another `self`; libuv because most of its functions exist once for Unix and once for Windows, and the build files, not the source, choose between them.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "descry-codegraph"
3
- version = "0.3.2"
3
+ version = "0.3.3"
4
4
  description = "Codebase knowledge graph: polyglot indexer, semantic search, call-graph analysis"
5
5
  requires-python = ">=3.11"
6
6
  authors = [{name = "Christian Haynes"}]
@@ -1,4 +1,4 @@
1
1
  """Descry — Codebase knowledge graph: polyglot indexer, semantic search, call-graph analysis."""
2
2
 
3
- __version__ = "0.3.2"
3
+ __version__ = "0.3.3"
4
4
  __all__ = ["__version__"]
@@ -18650,6 +18650,15 @@ class CallResolver:
18650
18650
  if self.standard[lang].key(callee, source_id) == callee:
18651
18651
  held = self._returned_type(constructed, source_id)
18652
18652
  self._result = held or self._result
18653
+ elif verdict[1] == _EXTERNAL and not origin and lang == "dart":
18654
+ # Dart constructs without `new`: a call of a standard type's
18655
+ # name gives an instance of it.
18656
+ library = self.standard[lang]
18657
+ if (
18658
+ callee in library.data["types"]
18659
+ and library.key(callee, source_id) == callee
18660
+ ):
18661
+ self._result = self._returned_type(callee, source_id) or self._result
18653
18662
  elif verdict[1] == _EXTERNAL and not origin and lang == "typescript":
18654
18663
  known, value = self._js_global(callee, source_id)
18655
18664
  if known:
@@ -24878,12 +24887,19 @@ class CodeGraphBuilder:
24878
24887
  for root, dirs, files in os.walk(self.root_dir, followlinks=False):
24879
24888
  dirs.sort()
24880
24889
  files.sort()
24881
- # Filter by name first (excluded dirs, dotfiles), and by what git
24882
- # ignores.
24890
+ # Filter by name first (excluded dirs, dotfiles, the build output
24891
+ # of a .NET or an Eclipse project), and by what git ignores.
24892
+ # `bin` holds sources in Dart and Rust.
24893
+ built = any(
24894
+ f.endswith((".csproj", ".vbproj", ".fsproj")) or f == ".classpath"
24895
+ for f in files
24896
+ )
24883
24897
  dirs[:] = [
24884
24898
  d
24885
24899
  for d in kept(root, dirs)
24886
- if not d.startswith(".") and d not in self.excluded_dirs
24900
+ if not d.startswith(".")
24901
+ and d not in self.excluded_dirs
24902
+ and not (built and d == "bin")
24887
24903
  ]
24888
24904
  # Then filter by realpath containment — drop directories that are
24889
24905
  # symlinks pointing outside the project root.
@@ -92,8 +92,8 @@ _DEFAULT_EXCLUDED_DIRS = {
92
92
  "venv",
93
93
  # Go
94
94
  "vendor",
95
- # .NET
96
- "bin",
95
+ # .NET (its `bin`, and an Eclipse project's, is skipped beside the
96
+ # project file)
97
97
  "obj",
98
98
  # Dart / Flutter
99
99
  ".dart_tool",
@@ -30858,3 +30858,51 @@ def test_a_form_feed_ends_no_line(tmp_path):
30858
30858
  }
30859
30859
  assert len(found) == 11
30860
30860
  assert set(found.values()) == {3}
30861
+
30862
+
30863
+ def test_a_bin_directory_is_indexed_unless_it_is_dotnet_build_output(tmp_path):
30864
+ """Dart's `bin/` and Rust's `src/bin/` hold sources; a .NET or an
30865
+ Eclipse project's `bin/` holds what it builds."""
30866
+ from descry.handlers import _DEFAULT_EXCLUDED_DIRS
30867
+
30868
+ files = {
30869
+ "dart/bin/main.dart": "void main() {}\n",
30870
+ "rust/src/bin/tool.rs": "fn main() {}\n",
30871
+ "net/App.csproj": "<Project />\n",
30872
+ "net/bin/Debug/Copied.cs": "class Copied {}\n",
30873
+ "eclipse/.classpath": "<classpath />\n",
30874
+ "eclipse/bin/generated/Copied.java": "class Copied {}\n",
30875
+ }
30876
+ for rel, source in files.items():
30877
+ (tmp_path / rel).parent.mkdir(parents=True, exist_ok=True)
30878
+ (tmp_path / rel).write_text(source)
30879
+ builder = CodeGraphBuilder(tmp_path, excluded_dirs=set(_DEFAULT_EXCLUDED_DIRS))
30880
+ builder.process_directory()
30881
+ found = {n["id"] for n in builder.nodes if n["type"] == "File"}
30882
+ assert {"FILE:dart/bin/main.dart", "FILE:rust/src/bin/tool.rs"} <= found
30883
+ assert not any(
30884
+ "/bin/" in f for f in found if f.startswith(("FILE:net", "FILE:eclipse"))
30885
+ )
30886
+
30887
+
30888
+ def test_a_dart_call_of_a_standard_type_constructs_it(tmp_path):
30889
+ """Dart needs no `new`: `StringBuffer()` makes a StringBuffer, whose
30890
+ `toString` is the library's, not a project method of that name."""
30891
+ builder = _index(
30892
+ tmp_path,
30893
+ {
30894
+ "pubspec.yaml": "name: x\n",
30895
+ "lib/a.dart": """
30896
+ class Oops {
30897
+ @override
30898
+ String toString() => 'oops';
30899
+ }
30900
+
30901
+ String build() {
30902
+ final sb = StringBuffer();
30903
+ return sb.toString();
30904
+ }
30905
+ """,
30906
+ },
30907
+ )
30908
+ assert _calls(builder, "FILE:lib/a.dart::build") == []