graphlint 0.3.0__tar.gz → 0.3.2__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 (116) hide show
  1. {graphlint-0.3.0 → graphlint-0.3.2}/CHANGELOG.md +275 -243
  2. {graphlint-0.3.0/graphlint.egg-info → graphlint-0.3.2}/PKG-INFO +4 -3
  3. {graphlint-0.3.0 → graphlint-0.3.2}/README.md +200 -199
  4. {graphlint-0.3.0 → graphlint-0.3.2}/README_PYPI.md +200 -199
  5. {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/architecture/overview.md +51 -0
  6. {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/README.md +200 -199
  7. {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/architecture/overview.md +44 -0
  8. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/__init__.py +1 -1
  9. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/_graph_algo.py +43 -23
  10. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/graph.py +595 -594
  11. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/python/imports.py +14 -1
  12. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/rust/constants.py +317 -258
  13. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/rust/entry.py +360 -332
  14. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/rust/imports.py +171 -171
  15. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/api.py +12 -2
  16. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/config/defaults.py +7 -0
  17. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/incremental/_db_ops.py +35 -1
  18. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/incremental/indexer.py +421 -381
  19. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/query/engine.py +56 -28
  20. {graphlint-0.3.0 → graphlint-0.3.2/graphlint.egg-info}/PKG-INFO +4 -3
  21. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint.egg-info/requires.txt +1 -1
  22. {graphlint-0.3.0 → graphlint-0.3.2}/pyproject.toml +2 -2
  23. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_engine.py +86 -0
  24. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_imports.py +43 -0
  25. {graphlint-0.3.0 → graphlint-0.3.2}/CONTRIBUTING.md +0 -0
  26. {graphlint-0.3.0 → graphlint-0.3.2}/LICENSE +0 -0
  27. {graphlint-0.3.0 → graphlint-0.3.2}/MANIFEST.in +0 -0
  28. {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/api/build.md +0 -0
  29. {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/api/configure.md +0 -0
  30. {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/api/exceptions.md +0 -0
  31. {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/api/query.md +0 -0
  32. {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/cli/usage.md +0 -0
  33. {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/guide/agent-integration.md +0 -0
  34. {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/guide/configuration.md +0 -0
  35. {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/guide/entry-detection.md +0 -0
  36. {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/guide/getting-started.md +0 -0
  37. {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/guide/warnings.md +0 -0
  38. {graphlint-0.3.0 → graphlint-0.3.2}/docs/en/index.md +0 -0
  39. {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/api/build.md +0 -0
  40. {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/api/configure.md +0 -0
  41. {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/api/exceptions.md +0 -0
  42. {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/api/query.md +0 -0
  43. {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/cli/usage.md +0 -0
  44. {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/guide/agent-integration.md +0 -0
  45. {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/guide/configuration.md +0 -0
  46. {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/guide/entry-detection.md +0 -0
  47. {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/guide/getting-started.md +0 -0
  48. {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/guide/warnings.md +0 -0
  49. {graphlint-0.3.0 → graphlint-0.3.2}/docs/zh/index.md +0 -0
  50. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/agent_tools.py +0 -0
  51. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/__init__.py +0 -0
  52. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/_types.py +0 -0
  53. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/__init__.py +0 -0
  54. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/base.py +0 -0
  55. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/python/__init__.py +0 -0
  56. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/python/constants.py +0 -0
  57. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/python/decorators.py +0 -0
  58. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/python/entry.py +0 -0
  59. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/python/parser.py +0 -0
  60. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/python/visitor.py +0 -0
  61. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/registry.py +0 -0
  62. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/rust/__init__.py +0 -0
  63. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/rust/parser.py +0 -0
  64. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/language/rust/visitor.py +0 -0
  65. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/analyzer/warnings.py +0 -0
  66. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/cli.py +0 -0
  67. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/config/__init__.py +0 -0
  68. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/config/manager.py +0 -0
  69. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/exceptions.py +0 -0
  70. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/i18n/__init__.py +0 -0
  71. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/i18n/en.py +0 -0
  72. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/i18n/zh_CN.py +0 -0
  73. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/incremental/__init__.py +0 -0
  74. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/params.py +0 -0
  75. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/query/__init__.py +0 -0
  76. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/query/formatter.py +0 -0
  77. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/query/volume.py +0 -0
  78. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/storage/__init__.py +0 -0
  79. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/storage/db.py +0 -0
  80. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/storage/hashing.py +0 -0
  81. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint/storage/schema.py +0 -0
  82. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint.egg-info/SOURCES.txt +0 -0
  83. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint.egg-info/dependency_links.txt +0 -0
  84. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint.egg-info/entry_points.txt +0 -0
  85. {graphlint-0.3.0 → graphlint-0.3.2}/graphlint.egg-info/top_level.txt +0 -0
  86. {graphlint-0.3.0 → graphlint-0.3.2}/setup.cfg +0 -0
  87. {graphlint-0.3.0 → graphlint-0.3.2}/tests/__init__.py +0 -0
  88. {graphlint-0.3.0 → graphlint-0.3.2}/tests/integration/__init__.py +0 -0
  89. {graphlint-0.3.0 → graphlint-0.3.2}/tests/integration/test_api.py +0 -0
  90. {graphlint-0.3.0 → graphlint-0.3.2}/tests/integration/test_cli.py +0 -0
  91. {graphlint-0.3.0 → graphlint-0.3.2}/tests/integration/test_data_transfer.py +0 -0
  92. {graphlint-0.3.0 → graphlint-0.3.2}/tests/integration/test_dead_code_query.py +0 -0
  93. {graphlint-0.3.0 → graphlint-0.3.2}/tests/integration/test_full_pipeline.py +0 -0
  94. {graphlint-0.3.0 → graphlint-0.3.2}/tests/integration/test_incremental.py +0 -0
  95. {graphlint-0.3.0 → graphlint-0.3.2}/tests/integration/test_json_output.py +0 -0
  96. {graphlint-0.3.0 → graphlint-0.3.2}/tests/performance/__init__.py +0 -0
  97. {graphlint-0.3.0 → graphlint-0.3.2}/tests/performance/test_large_codebase.py +0 -0
  98. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/__init__.py +0 -0
  99. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_auto_build.py +0 -0
  100. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_config.py +0 -0
  101. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_db.py +0 -0
  102. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_db_ops.py +0 -0
  103. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_decorators.py +0 -0
  104. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_entry_detect.py +0 -0
  105. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_exceptions.py +0 -0
  106. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_formatter.py +0 -0
  107. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_graph.py +0 -0
  108. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_graph_algo.py +0 -0
  109. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_hashing.py +0 -0
  110. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_i18n.py +0 -0
  111. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_mock_boundary.py +0 -0
  112. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_params.py +0 -0
  113. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_parser.py +0 -0
  114. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_schema.py +0 -0
  115. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_volume.py +0 -0
  116. {graphlint-0.3.0 → graphlint-0.3.2}/tests/unit/test_warnings.py +0 -0
@@ -1,243 +1,275 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- ## [0.3.0] - 2026-07-23
6
-
7
- ### Added
8
- - Experimental Rust language analysis via `tree-sitter-rust` (opt-in via `[rust]`
9
- optional dependency group)
10
- - `query --public-as-entry` option: treats all public functions/methods as entry
11
- points for dead-code reachability analysis
12
- - `pub_api` entry rule template (disabled by default) for projects that want
13
- public API surface as the primary entry
14
-
15
-
16
- ## [0.2.0] - 2026-07-22
17
-
18
- ### Added
19
- - Multi-language architecture: `LanguageAdapter` abstract base class and
20
- `LanguageRegistry` for extension-based routing of source files to language
21
- backends, laying the foundation for future multi-language support
22
- - `language/python/` package: Python-specific adapter, parser, entry detector,
23
- imports analyzer, decorators resolver, and constants — decoupled from the
24
- core framework
25
- - Per-language `constants.py`: configurable public API dunders, special
26
- methods, and test-file detection
27
- - Type annotation awareness in AST visitor: automatically resolves unpacked
28
- variable types (e.g., loop bindings, tuple unpacking) for more accurate
29
- read/write edge tracking
30
-
31
- ### Changed
32
- - **[Breaking]** Analyzer modules reorganized: `parser.py`, `entry_detect.py`,
33
- `imports.py`, `decorators.py`, `visitor.py` moved into `language/python/` —
34
- direct imports of old module paths will break
35
- - Entry point rules now serve as initialization template only: rules are
36
- written to `.graphlint/config.json` on first build, after which the config
37
- file is the single source of truth
38
- - Default entry strategy simplified: entry rules are no longer hardcoded in
39
- the indexer; they come solely from runtime configuration
40
- - `GraphBuilder` no longer owns entry detection — entry points are resolved
41
- through the language adapter
42
- - `WarningCollector` simplified: language-specific constant tables moved to
43
- `language/python/constants.py`
44
-
45
- ## [0.1.12] - 2026-07-21
46
-
47
- ### Added
48
- - `query --fail-on <warn-types>` option: returns exit code `2` when matching
49
- warning types are found in query results, enabling CI pipeline integration
50
- - `graphlint config` subcommands now return exit code `1` on error (previously
51
- always returned `0`)
52
-
53
- ## [0.1.11] - 2026-07-21
54
-
55
- ### Changed
56
- - Entry point detection now uses a unified pattern-driven architecture — all
57
- rules (built-in and custom) share the same `_detect_custom` code path
58
- - Built-in detectors replaced with declarative `ast_pattern` expressions using
59
- the existing prefix syntax (`function_call:`, `decorator:`, `if_name_main`,
60
- `file_match:`, `test_file`)
61
- - `ast_pattern` supports OR combinations with ` | ` separator (e.g.
62
- `class_instantiation:FastAPI | function_call:uvicorn.run`)
63
- - `ast_pattern` field is no longer required for entry rules — rules without
64
- it are silently skipped instead of failing validation
65
- - Decorator matching uses `fnmatch` instead of substring `in`, providing
66
- precise glob matching and eliminating false positives from partial name
67
- overlaps
68
- - `function_call:` and `class_instantiation:` patterns now support `fnmatch`
69
- globs (was exact match only)
70
-
71
- ### Fixed
72
- - `file_match:` pattern now correctly checks the file path at rule level
73
- instead of a non-existent `node.filename` attribute, fixing the bug where
74
- `file_match:` rules never matched
75
- - `graphlint config copy-from` no longer picks up irrelevant query/analyzer
76
- parameters, fixing the config copy command exception
77
-
78
- ## [0.1.10] - 2026-07-09
79
-
80
- ### Fixed
81
- - Assignment target context resolution now correctly distinguishes class fields
82
- (`self.xxx` / `cls.xxx`), method-local variables, and module-level variables,
83
- preventing misclassification of `self.x = y` inside methods as local variables
84
- - Class fields assigned across multiple methods (e.g. `__init__` + `set_x`) are
85
- now deduplicated to a single node, eliminating duplicate field nodes
86
-
87
- ### Changed
88
- - Attribute-write edges (`self.xxx = value`) now also emit a `read` edge on
89
- the parent object (`self`), ensuring proper usage tracking of the containing
90
- class instance
91
-
92
- ## [0.1.9] - 2026-07-08
93
-
94
- ### Fixed
95
- - FOREIGN KEY constraint failure on incremental rebuilds — prebuilt edge
96
- remapping now correctly writes remapped node IDs into edge objects
97
- - `_insert_nodes` node-to-file key collision when multiple changed files
98
- share the same qualified name and line number
99
-
100
- ### Changed
101
- - Incremental rebuild now parses only changed files instead of all files
102
- - Filesystem scan merged into a single `os.walk` pass instead of two
103
- - Redundant file hash computation eliminated in both full and incremental paths
104
-
105
- ### Added
106
- - `component_members` table in SQLite schema for future incremental
107
- connectivity analysis
108
-
109
- ## [0.1.8] - 2026-07-07
110
-
111
- ### Added
112
- - Agent prompt auto-update: `install` now scans all installed prompts on start,
113
- replaces outdated content when its version is below the library version,
114
- and prints the list of updated agents
115
- - `install` / `uninstall` interactive selection: support Ctrl+C to abort and
116
- empty input to cancel; prompt texts are now i18n-localized
117
- - `graphlint prompt` subcommand to copy the agent prompt to the system clipboard
118
- - Documentation for agent integration (`docs/*/guide/agent-integration.md`)
119
-
120
- ### Fixed
121
- - Query deadlock: `_build_edge_mapping` now avoids `result` future list
122
- mutation under concurrent executor shutdown, preventing infinite waits
123
-
124
- ## [0.1.7] - 2026-07-06
125
-
126
- ### Fixed
127
- - `_resolve_symbol` scope filtering no longer drops cross-class `call` edges
128
- when a method resolves a same-named call via a different class (registry
129
- / dispatch pattern) — all suffix-matched candidates are now included
130
- - Entry point `file_pattern` matching (`**/*.py` via fnmatch) now also
131
- matches root-level Python files, not only files in subdirectories
132
-
133
- ## [0.1.6] - 2026-07-05
134
-
135
- ### Changed
136
- - `ThreadPoolExecutor` replaced with `ProcessPoolExecutor` for edge building
137
- - Incremental builds on file change now trigger a full rebuild instead of loading prebuilt edges
138
- - Module-level usage expansion in connected-component analysis uses a Counter to distinguish real references from synthetic edges
139
- - Dead-code merge loop uses O(1) `comp_by_id` dict lookup instead of O(C) linear scan
140
-
141
- ### Removed
142
- - `_quick_changed_check()` — mtime-based fast-path stamp was unreliable on Windows NTFS and could trigger unnecessary incremental builds that produced stale edges
143
- - Ghost-node insertion workaround and stale-edge skip logic in `_do_insert_edges`
144
-
145
- ## [0.1.5] - 2026-07-05
146
-
147
- ### Added
148
- - `global` keyword support: `visit_Global` handler tracks names declared as `global X` and resolves references to module-level qualified names (`module.X`) instead of local ones, preventing false local node creation
149
- - `visit_AugAssign` handler for augmented assignment (`X += 1`, `X *= 2`, etc.), generating both read and write references to the target
150
- - Scope isolation for `global` declarations — `_global_names` is saved/restored on function entry/exit, preventing leakage between functions
151
-
152
- ### Fixed
153
- - `global X` in functions/methods no longer creates spurious local variable nodes for globally-declared names
154
- - Augmented assignment (`X += 1`) was silently dropped during AST traversal — now correctly produces both read and write edges
155
-
156
- ## [0.1.4] - 2026-07-04
157
-
158
- ### Fixed
159
- - Module-level dead code detection: removed synthetic `read` edges from pseudo-node 0 that masked all top-level symbols as "used", enabling detection of genuinely dead module-level functions and variables
160
- - Module-level write references no longer create unresolvable edges — variable definitions are not treated as write operations, preventing silent edge drops
161
- - Module-level read/call references now correctly create edges from pseudo-node 0, fixing a false positive where module-level used variables (e.g., `WARN_TYPE_VALUES` read by `VALID_WARN_TYPES = WARN_TYPE_VALUES`) were flagged as dead code
162
- - Public API dunders (`__all__`, `__version__`, etc.) no longer appear as isolated components — they stay anchored to their file via synthetic containment edges
163
- - Python special methods (`__init__`, `__enter__`, `__exit__`, etc.) no longer generate redundant dead-code warnings when their parent class is already flagged as unreachable
164
- - Unreachable classes with special method overloads now produce only the class-level `dead_code` warning, not per-method duplicates
165
-
166
- ## [0.1.3] - 2026-07-04
167
-
168
- ### Added
169
- - I18n support for CLI parameter help text: `PARAM_DEFS` help strings now go through the i18n system via `help_key`, enabling full language switching for `--help` output
170
-
171
- ### Changed
172
- - `ParamDef` dataclass: added `help_key` field for i18n key lookup
173
- - `cli.py:_add_arg()` now resolves help text via `_t(help_key)` when available
174
- - Updated `en.py` and `zh_CN.py` with all `help.param.*` translation entries
175
-
176
- ## [0.1.2] - 2026-07-04
177
-
178
- ### Added
179
- - SQLite composite indexes (`idx_edges_source_type`, `idx_edges_target_type`) to accelerate edge-type filtered lookups
180
- - SQLite single-column index (`idx_warnings_node`) to speed up warnings JOIN queries
181
- - SQLite sorted indexes (`idx_snapshots_warnings`, `idx_snapshots_nodes`) for faster list_graphs pagination
182
- - PRAGMA optimizations on Database init: `cache_size=-8000` (8 MB), `mmap_size=268435456` (256 MB), `temp_store=MEMORY`
183
- - `_quick_changed_check()` — mtime-based fast-path stamp that short-circuits the entire build when no files have changed
184
- - `_update_scan_stamp()` — persists `{path: mtime_ns}` snapshot inside IndexLock after each successful build
185
- - `warnings_summary` cache in `QueryEngine.list_graphs()` — lazily computed then shallow-copied, eliminating repeated `GROUP BY` scans
186
- - `_precompute_edge_counts()` — single-pass edge count per component, replacing O(n × m) per-component iteration
187
-
188
- ### Changed
189
- - Eliminated second AST traversal: edge building is now driven by `ReferenceInfo` collected during the single `ASTVisitor` pass — removed `_walk`, `_read_edges`, `_proc_call`, `_proc_assign`, `_proc_annassign`, `_target_ids`, `_read_target_expr` (~400 lines). In a large codebase (700+ `.py` files, 1000+ classes, 14,000+ functions), full rebuild time improved from ~2500s to ~200s.
190
- - `_build_file_edges_worker` now consumes `ParseResult.references` directly instead of re-walking the AST tree
191
- - Module pseudo-node (id=0) connectivity tightened: liveness only propagates through `read`/`call` edges, not `write` edges — preventing false reachability of write-only variables and fixing false dead-code reports for module-level used variables
192
- - Connected component BFS no longer unconditionally seeds node 0, avoiding spurious reachability
193
- - Module-level synthetic edges recreated for all files each build instead of only for unchanged files
194
- - Optimized multiple AST I/O bottlenecks in source file reading and tree reuse
195
- - `_symbol_index` / `_suffix_index` from `dict` to `defaultdict(list)`, removing all `.setdefault()` calls
196
- - `_resolve_symbol` now accepts a per-worker `resolve_cache` dict — repeated `(qname, scope)` pairs are resolved once per file
197
- - `call_graph` prebuilt once in `find_connected_components` and reused across `compute_entry_reachability` calls, eliminating redundant edge re-traversal
198
- - `_insert_nodes` uses a pre-built `(qualified_name, line_start) → file_path` map instead of O(n²) linear scan via `_node_path()`
199
- - Full rebuild (`incremental=False`) now uses per-table `DELETE FROM` instead of per-file `_delete_old` + selective cleanup
200
- - Incremental build edge insertion now uses global `DELETE FROM edges` instead of per-file partial delete, eliminating dangling old node-ID references
201
- - `load_prebuilt_edges` accepts optional `sql_to_mem` mapping, simplifying caller in `indexer.py`
202
- - Agent injection prompt strengthened to warn when graphlint CLI is unavailable
203
-
204
- ### Removed
205
- - `_node_path()` helper function (replaced by pre-built node-to-file map)
206
-
207
- ### Fixed
208
- - Windows compatibility: `os.unlink()` with `missing_ok=True` replaced by `if exists()` guard
209
-
210
- ## [0.1.1] - 2026-07-04
211
-
212
- ### Added
213
- - Parallel edge building via ThreadPoolExecutor for changed files (`performance.parallel_workers`)
214
- - Multi-level suffix index for improved symbol resolution beyond single-level short names
215
- - Auto-build retry with full index rebuild on FOREIGN KEY constraint failure
216
-
217
- ### Changed
218
- - Agent injection prompt wording strengthened to "Always use" with fallback instruction when CLI is unavailable
219
- - Entry detection methods now reuse pre-parsed source (`pr.source`) to reduce redundant file I/O
220
- - Refactored AST walk functions to module level to enable parallel execution
221
-
222
- ### Fixed
223
- - FOREIGN KEY constraint violations in incremental mode by sorting nodes parent-first before DB insert
224
- - Incremental rebuild no longer rebuilds edges for unchanged files
225
-
226
- ## [0.1.0] - 2026-07-01
227
-
228
- ### Added
229
- - Initial release
230
- - AST-based Python source code parsing (classes, functions, methods, variables, fields)
231
- - Dependency graph construction with 5 edge types (read, write, call, inherit, decorate)
232
- - 8 built-in entry point detection rules (main, FastAPI, Flask, Django, Click, Typer, Celery, pytest)
233
- - Custom entry point rules via AST pattern matching
234
- - 11 warning types (unused_import, dynamic_import, circular_ref, syntax_error, write_only, deprecated_usage, dead_code, type_mismatch, unresolved_ref, unused_variable, file_too_large)
235
- - Incremental indexing with SHA256-based change detection
236
- - Adaptive output volume strategy (full, index, truncated)
237
- - Internationalization (English and Simplified Chinese)
238
- - CLI interface (`graphlint query`, `graphlint build`, `graphlint config`)
239
- - Python API (`query()`, `build()`, `configure()`)
240
- - SQLite persistence with cross-platform file locking
241
- - Parallel file parsing via ProcessPoolExecutor
242
- - Configuration management with dot-notation key access
243
- - Comprehensive test suite (unit, integration, performance)
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ ## [0.3.2] - 2026-07-25
6
+
7
+ ### Changed
8
+ - First-time builds now run a full rebuild; all subsequent queries use
9
+ incremental mode (previously every query forced a full rebuild)
10
+ - Incremental rebuild restructured into 6 clearly delineated phases: Remove →
11
+ Parse → Downstream Reconnect → Rebuild → Persist → Verify
12
+
13
+ ### Fixed
14
+ - Incremental rebuild: empty `set()` passed as `changed_files` was treated as
15
+ falsy and replaced with all files, causing unnecessary full re-parse
16
+ - Incremental rebuild: unchanged child nodes whose parent received a new ID in
17
+ a changed file had stale `parent_node_id` values in the database (in-memory
18
+ remapping was not written back)
19
+ - Incremental rebuild: removed files were not included in downstream
20
+ reconnection, causing FOREIGN KEY violations when prebuilt edges referenced
21
+ deleted symbols
22
+
23
+ ## [0.3.1] - 2026-07-24
24
+
25
+ ### Added
26
+ - Cargo workspace detection: `[[bin]]` path entries in `Cargo.toml` are now
27
+ recognized as Rust language entry points
28
+
29
+ ### Fixed
30
+ - SQLite `IN` clause batching: queries with >999 variables are now split into
31
+ batches to avoid the SQLite variable limit, preventing crashes on large
32
+ codebases
33
+ - Dotted imports (`import X.Y.Z`) are now correctly detected as used, fixing
34
+ false-positive `unused_import` warnings for multi-level imports
35
+ - Relaxed `tree-sitter-rust` version bound to allow Rust grammar v15+
36
+
37
+ ## [0.3.0] - 2026-07-23
38
+
39
+ ### Added
40
+ - Experimental Rust language analysis via `tree-sitter-rust` (opt-in via `[rust]`
41
+ optional dependency group)
42
+ - `query --public-as-entry` option: treats all public functions/methods as entry
43
+ points for dead-code reachability analysis
44
+ - `pub_api` entry rule template (disabled by default) for projects that want
45
+ public API surface as the primary entry
46
+
47
+
48
+ ## [0.2.0] - 2026-07-22
49
+
50
+ ### Added
51
+ - Multi-language architecture: `LanguageAdapter` abstract base class and
52
+ `LanguageRegistry` for extension-based routing of source files to language
53
+ backends, laying the foundation for future multi-language support
54
+ - `language/python/` package: Python-specific adapter, parser, entry detector,
55
+ imports analyzer, decorators resolver, and constants — decoupled from the
56
+ core framework
57
+ - Per-language `constants.py`: configurable public API dunders, special
58
+ methods, and test-file detection
59
+ - Type annotation awareness in AST visitor: automatically resolves unpacked
60
+ variable types (e.g., loop bindings, tuple unpacking) for more accurate
61
+ read/write edge tracking
62
+
63
+ ### Changed
64
+ - **[Breaking]** Analyzer modules reorganized: `parser.py`, `entry_detect.py`,
65
+ `imports.py`, `decorators.py`, `visitor.py` moved into `language/python/` —
66
+ direct imports of old module paths will break
67
+ - Entry point rules now serve as initialization template only: rules are
68
+ written to `.graphlint/config.json` on first build, after which the config
69
+ file is the single source of truth
70
+ - Default entry strategy simplified: entry rules are no longer hardcoded in
71
+ the indexer; they come solely from runtime configuration
72
+ - `GraphBuilder` no longer owns entry detection — entry points are resolved
73
+ through the language adapter
74
+ - `WarningCollector` simplified: language-specific constant tables moved to
75
+ `language/python/constants.py`
76
+
77
+ ## [0.1.12] - 2026-07-21
78
+
79
+ ### Added
80
+ - `query --fail-on <warn-types>` option: returns exit code `2` when matching
81
+ warning types are found in query results, enabling CI pipeline integration
82
+ - `graphlint config` subcommands now return exit code `1` on error (previously
83
+ always returned `0`)
84
+
85
+ ## [0.1.11] - 2026-07-21
86
+
87
+ ### Changed
88
+ - Entry point detection now uses a unified pattern-driven architecture — all
89
+ rules (built-in and custom) share the same `_detect_custom` code path
90
+ - Built-in detectors replaced with declarative `ast_pattern` expressions using
91
+ the existing prefix syntax (`function_call:`, `decorator:`, `if_name_main`,
92
+ `file_match:`, `test_file`)
93
+ - `ast_pattern` supports OR combinations with ` | ` separator (e.g.
94
+ `class_instantiation:FastAPI | function_call:uvicorn.run`)
95
+ - `ast_pattern` field is no longer required for entry rules — rules without
96
+ it are silently skipped instead of failing validation
97
+ - Decorator matching uses `fnmatch` instead of substring `in`, providing
98
+ precise glob matching and eliminating false positives from partial name
99
+ overlaps
100
+ - `function_call:` and `class_instantiation:` patterns now support `fnmatch`
101
+ globs (was exact match only)
102
+
103
+ ### Fixed
104
+ - `file_match:` pattern now correctly checks the file path at rule level
105
+ instead of a non-existent `node.filename` attribute, fixing the bug where
106
+ `file_match:` rules never matched
107
+ - `graphlint config copy-from` no longer picks up irrelevant query/analyzer
108
+ parameters, fixing the config copy command exception
109
+
110
+ ## [0.1.10] - 2026-07-09
111
+
112
+ ### Fixed
113
+ - Assignment target context resolution now correctly distinguishes class fields
114
+ (`self.xxx` / `cls.xxx`), method-local variables, and module-level variables,
115
+ preventing misclassification of `self.x = y` inside methods as local variables
116
+ - Class fields assigned across multiple methods (e.g. `__init__` + `set_x`) are
117
+ now deduplicated to a single node, eliminating duplicate field nodes
118
+
119
+ ### Changed
120
+ - Attribute-write edges (`self.xxx = value`) now also emit a `read` edge on
121
+ the parent object (`self`), ensuring proper usage tracking of the containing
122
+ class instance
123
+
124
+ ## [0.1.9] - 2026-07-08
125
+
126
+ ### Fixed
127
+ - FOREIGN KEY constraint failure on incremental rebuilds — prebuilt edge
128
+ remapping now correctly writes remapped node IDs into edge objects
129
+ - `_insert_nodes` node-to-file key collision when multiple changed files
130
+ share the same qualified name and line number
131
+
132
+ ### Changed
133
+ - Incremental rebuild now parses only changed files instead of all files
134
+ - Filesystem scan merged into a single `os.walk` pass instead of two
135
+ - Redundant file hash computation eliminated in both full and incremental paths
136
+
137
+ ### Added
138
+ - `component_members` table in SQLite schema for future incremental
139
+ connectivity analysis
140
+
141
+ ## [0.1.8] - 2026-07-07
142
+
143
+ ### Added
144
+ - Agent prompt auto-update: `install` now scans all installed prompts on start,
145
+ replaces outdated content when its version is below the library version,
146
+ and prints the list of updated agents
147
+ - `install` / `uninstall` interactive selection: support Ctrl+C to abort and
148
+ empty input to cancel; prompt texts are now i18n-localized
149
+ - `graphlint prompt` subcommand to copy the agent prompt to the system clipboard
150
+ - Documentation for agent integration (`docs/*/guide/agent-integration.md`)
151
+
152
+ ### Fixed
153
+ - Query deadlock: `_build_edge_mapping` now avoids `result` future list
154
+ mutation under concurrent executor shutdown, preventing infinite waits
155
+
156
+ ## [0.1.7] - 2026-07-06
157
+
158
+ ### Fixed
159
+ - `_resolve_symbol` scope filtering no longer drops cross-class `call` edges
160
+ when a method resolves a same-named call via a different class (registry
161
+ / dispatch pattern) — all suffix-matched candidates are now included
162
+ - Entry point `file_pattern` matching (`**/*.py` via fnmatch) now also
163
+ matches root-level Python files, not only files in subdirectories
164
+
165
+ ## [0.1.6] - 2026-07-05
166
+
167
+ ### Changed
168
+ - `ThreadPoolExecutor` replaced with `ProcessPoolExecutor` for edge building
169
+ - Incremental builds on file change now trigger a full rebuild instead of loading prebuilt edges
170
+ - Module-level usage expansion in connected-component analysis uses a Counter to distinguish real references from synthetic edges
171
+ - Dead-code merge loop uses O(1) `comp_by_id` dict lookup instead of O(C) linear scan
172
+
173
+ ### Removed
174
+ - `_quick_changed_check()` — mtime-based fast-path stamp was unreliable on Windows NTFS and could trigger unnecessary incremental builds that produced stale edges
175
+ - Ghost-node insertion workaround and stale-edge skip logic in `_do_insert_edges`
176
+
177
+ ## [0.1.5] - 2026-07-05
178
+
179
+ ### Added
180
+ - `global` keyword support: `visit_Global` handler tracks names declared as `global X` and resolves references to module-level qualified names (`module.X`) instead of local ones, preventing false local node creation
181
+ - `visit_AugAssign` handler for augmented assignment (`X += 1`, `X *= 2`, etc.), generating both read and write references to the target
182
+ - Scope isolation for `global` declarations — `_global_names` is saved/restored on function entry/exit, preventing leakage between functions
183
+
184
+ ### Fixed
185
+ - `global X` in functions/methods no longer creates spurious local variable nodes for globally-declared names
186
+ - Augmented assignment (`X += 1`) was silently dropped during AST traversal — now correctly produces both read and write edges
187
+
188
+ ## [0.1.4] - 2026-07-04
189
+
190
+ ### Fixed
191
+ - Module-level dead code detection: removed synthetic `read` edges from pseudo-node 0 that masked all top-level symbols as "used", enabling detection of genuinely dead module-level functions and variables
192
+ - Module-level write references no longer create unresolvable edges — variable definitions are not treated as write operations, preventing silent edge drops
193
+ - Module-level read/call references now correctly create edges from pseudo-node 0, fixing a false positive where module-level used variables (e.g., `WARN_TYPE_VALUES` read by `VALID_WARN_TYPES = WARN_TYPE_VALUES`) were flagged as dead code
194
+ - Public API dunders (`__all__`, `__version__`, etc.) no longer appear as isolated components — they stay anchored to their file via synthetic containment edges
195
+ - Python special methods (`__init__`, `__enter__`, `__exit__`, etc.) no longer generate redundant dead-code warnings when their parent class is already flagged as unreachable
196
+ - Unreachable classes with special method overloads now produce only the class-level `dead_code` warning, not per-method duplicates
197
+
198
+ ## [0.1.3] - 2026-07-04
199
+
200
+ ### Added
201
+ - I18n support for CLI parameter help text: `PARAM_DEFS` help strings now go through the i18n system via `help_key`, enabling full language switching for `--help` output
202
+
203
+ ### Changed
204
+ - `ParamDef` dataclass: added `help_key` field for i18n key lookup
205
+ - `cli.py:_add_arg()` now resolves help text via `_t(help_key)` when available
206
+ - Updated `en.py` and `zh_CN.py` with all `help.param.*` translation entries
207
+
208
+ ## [0.1.2] - 2026-07-04
209
+
210
+ ### Added
211
+ - SQLite composite indexes (`idx_edges_source_type`, `idx_edges_target_type`) to accelerate edge-type filtered lookups
212
+ - SQLite single-column index (`idx_warnings_node`) to speed up warnings JOIN queries
213
+ - SQLite sorted indexes (`idx_snapshots_warnings`, `idx_snapshots_nodes`) for faster list_graphs pagination
214
+ - PRAGMA optimizations on Database init: `cache_size=-8000` (8 MB), `mmap_size=268435456` (256 MB), `temp_store=MEMORY`
215
+ - `_quick_changed_check()` — mtime-based fast-path stamp that short-circuits the entire build when no files have changed
216
+ - `_update_scan_stamp()` — persists `{path: mtime_ns}` snapshot inside IndexLock after each successful build
217
+ - `warnings_summary` cache in `QueryEngine.list_graphs()` — lazily computed then shallow-copied, eliminating repeated `GROUP BY` scans
218
+ - `_precompute_edge_counts()` — single-pass edge count per component, replacing O(n × m) per-component iteration
219
+
220
+ ### Changed
221
+ - Eliminated second AST traversal: edge building is now driven by `ReferenceInfo` collected during the single `ASTVisitor` pass — removed `_walk`, `_read_edges`, `_proc_call`, `_proc_assign`, `_proc_annassign`, `_target_ids`, `_read_target_expr` (~400 lines). In a large codebase (700+ `.py` files, 1000+ classes, 14,000+ functions), full rebuild time improved from ~2500s to ~200s.
222
+ - `_build_file_edges_worker` now consumes `ParseResult.references` directly instead of re-walking the AST tree
223
+ - Module pseudo-node (id=0) connectivity tightened: liveness only propagates through `read`/`call` edges, not `write` edges — preventing false reachability of write-only variables and fixing false dead-code reports for module-level used variables
224
+ - Connected component BFS no longer unconditionally seeds node 0, avoiding spurious reachability
225
+ - Module-level synthetic edges recreated for all files each build instead of only for unchanged files
226
+ - Optimized multiple AST I/O bottlenecks in source file reading and tree reuse
227
+ - `_symbol_index` / `_suffix_index` from `dict` to `defaultdict(list)`, removing all `.setdefault()` calls
228
+ - `_resolve_symbol` now accepts a per-worker `resolve_cache` dict — repeated `(qname, scope)` pairs are resolved once per file
229
+ - `call_graph` prebuilt once in `find_connected_components` and reused across `compute_entry_reachability` calls, eliminating redundant edge re-traversal
230
+ - `_insert_nodes` uses a pre-built `(qualified_name, line_start) → file_path` map instead of O(n²) linear scan via `_node_path()`
231
+ - Full rebuild (`incremental=False`) now uses per-table `DELETE FROM` instead of per-file `_delete_old` + selective cleanup
232
+ - Incremental build edge insertion now uses global `DELETE FROM edges` instead of per-file partial delete, eliminating dangling old node-ID references
233
+ - `load_prebuilt_edges` accepts optional `sql_to_mem` mapping, simplifying caller in `indexer.py`
234
+ - Agent injection prompt strengthened to warn when graphlint CLI is unavailable
235
+
236
+ ### Removed
237
+ - `_node_path()` helper function (replaced by pre-built node-to-file map)
238
+
239
+ ### Fixed
240
+ - Windows compatibility: `os.unlink()` with `missing_ok=True` replaced by `if exists()` guard
241
+
242
+ ## [0.1.1] - 2026-07-04
243
+
244
+ ### Added
245
+ - Parallel edge building via ThreadPoolExecutor for changed files (`performance.parallel_workers`)
246
+ - Multi-level suffix index for improved symbol resolution beyond single-level short names
247
+ - Auto-build retry with full index rebuild on FOREIGN KEY constraint failure
248
+
249
+ ### Changed
250
+ - Agent injection prompt wording strengthened to "Always use" with fallback instruction when CLI is unavailable
251
+ - Entry detection methods now reuse pre-parsed source (`pr.source`) to reduce redundant file I/O
252
+ - Refactored AST walk functions to module level to enable parallel execution
253
+
254
+ ### Fixed
255
+ - FOREIGN KEY constraint violations in incremental mode by sorting nodes parent-first before DB insert
256
+ - Incremental rebuild no longer rebuilds edges for unchanged files
257
+
258
+ ## [0.1.0] - 2026-07-01
259
+
260
+ ### Added
261
+ - Initial release
262
+ - AST-based Python source code parsing (classes, functions, methods, variables, fields)
263
+ - Dependency graph construction with 5 edge types (read, write, call, inherit, decorate)
264
+ - 8 built-in entry point detection rules (main, FastAPI, Flask, Django, Click, Typer, Celery, pytest)
265
+ - Custom entry point rules via AST pattern matching
266
+ - 11 warning types (unused_import, dynamic_import, circular_ref, syntax_error, write_only, deprecated_usage, dead_code, type_mismatch, unresolved_ref, unused_variable, file_too_large)
267
+ - Incremental indexing with SHA256-based change detection
268
+ - Adaptive output volume strategy (full, index, truncated)
269
+ - Internationalization (English and Simplified Chinese)
270
+ - CLI interface (`graphlint query`, `graphlint build`, `graphlint config`)
271
+ - Python API (`query()`, `build()`, `configure()`)
272
+ - SQLite persistence with cross-platform file locking
273
+ - Parallel file parsing via ProcessPoolExecutor
274
+ - Configuration management with dot-notation key access
275
+ - Comprehensive test suite (unit, integration, performance)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: graphlint
3
- Version: 0.3.0
3
+ Version: 0.3.2
4
4
  Summary: A static analysis tool for identifying dead code in a codebase. It provides Python API and CLI for use by agents.
5
5
  Author-email: Yutong Zou <yutong.zou.24@alumni.ucl.ac.uk>
6
6
  License-Expression: MIT
@@ -28,7 +28,7 @@ Provides-Extra: dev
28
28
  Requires-Dist: pytest>=7; extra == "dev"
29
29
  Requires-Dist: pytest-cov>=4; extra == "dev"
30
30
  Provides-Extra: rust
31
- Requires-Dist: tree-sitter<0.25,>=0.22; extra == "rust"
31
+ Requires-Dist: tree-sitter<0.27,>=0.22; extra == "rust"
32
32
  Requires-Dist: tree-sitter-rust<0.25,>=0.22; extra == "rust"
33
33
  Dynamic: license-file
34
34
 
@@ -64,6 +64,7 @@ Install with Rust support: `pip install graphlint[rust]` (adds `tree-sitter` and
64
64
  - **Configurable entry templates** — add custom entry rules via `ast_pattern` prefixes including `function_call:`, `function_def:`, `decorator:`, `file_match:`, `visibility:pub` (Rust), `trait_impl:` (Rust), `macro_def:` (Rust), and more
65
65
  - **`--public-as-entry` flag** — treat all public items (Rust `pub`) as entry points for library-crate analysis
66
66
  - **Warning detection** — 11 warning types including circular references, unused imports, write-only variables, and more
67
+ - **Incremental updates** — after initial full scan, only changed files are re-indexed; subsequent queries leverage cached data to minimize computation overhead
67
68
  - **Python API + CLI** — integrate into any Tool, CI pipeline, or let agents self-analyze and self-clean
68
69
 
69
70
  ## Installation
@@ -220,7 +221,7 @@ Full documentation is available in the [docs/](https://github.com/AngelosZou/gra
220
221
  - **Python dynamic imports** — due to Python's dynamic import mechanisms (`importlib`, `getattr`, metaclasses, etc.), the default entry templates may produce false positives in codebases that rely heavily on runtime dispatch. Users should tune the `entry_rules` configuration to match their project's conventions.
221
222
  - **Rust macro expansion** — tree-sitter parses unexpanded source; procedural macros and `macro_rules!` bodies appear as opaque token trees. Some macro-generated call paths may be missed. `#[derive]` attributes are partially recognized via implicit `inherit` edges.
222
223
  - **`--public-as-entry` scope** — this flag only applies to languages with `public` visibility declarations (Rust `pub`). It has no effect on Python files. Toggling this flag triggers a full re-index. For long-term library-crate analysis, prefer enabling the `rust_pub_api` entry rule via `graphlint config` to persist the setting.
223
- - **Large codebase build time** — on a large codebase with 700+ `.py` files, 1,000+ classes, and 14,000+ functions, a full rebuild takes approximately 200 seconds (actual performance depends on hardware). Small projects (~60 files) complete in ~1 second. **Best practice:** run `query` before making changes to plan your work, and avoid invoking `query` during refactoring to prevent unnecessary index rebuilds.
224
+ - **Large codebase build time** — on a large codebase with 700+ `.py` files, 1,000+ classes, and 14,000+ functions, a full rebuild takes approximately 200 seconds (actual performance depends on hardware). Small projects (~60 files) complete in ~1 second. This cost is one-time, after the initial full scan, subsequent queries use incremental updates.
224
225
 
225
226
  ## License
226
227