node-walk 0.4.0__tar.gz → 0.5.0__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.
- {node_walk-0.4.0 → node_walk-0.5.0}/.github/workflows/ci.yml +8 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/CHANGELOG.md +28 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/PKG-INFO +1 -1
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/resolution/calls.py +1 -1
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/resolution/receiver.py +30 -9
- {node_walk-0.4.0 → node_walk-0.5.0}/.github/workflows/release.yml +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/.gitignore +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/LICENSE +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/README.md +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/plans/binding-and-receiver-resolution-plan.md +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/plans/graph-explorer-ux-plan.md +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/plans/plan.md +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/plans/receiver-resolution-plan.md +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/plans/relationship-resolution-redesign.md +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/plans/traversable-graph.md +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/pyproject.toml +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/__init__.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/analysis/__init__.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/analysis/base.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/analysis/python/__init__.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/analysis/python/analyzer.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/analysis/python/scope.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/analysis/python/visitor.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/analysis/python_analyzer.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/cli/__init__.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/cli/main.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/indexer.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/ir/__init__.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/ir/enums.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/ir/models.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/query/__init__.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/query/engine.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/query/tree_formatter.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/resolution/__init__.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/resolution/base.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/resolution/bindings.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/resolution/imports.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/resolution/inheritance.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/storage/__init__.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/storage/base.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/storage/repository.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/storage/schema.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/storage/sqlite_store.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/web/__init__.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/web/app.js +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/web/index.html +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/web/server.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/src/node_walk/web/style.css +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/tests/fixtures/nested_project/base.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/tests/fixtures/nested_project/impl.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/tests/fixtures/simple_project/services.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/tests/test_indexer.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/tests/test_ir.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/tests/test_python_analyzer.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/tests/test_query_engine.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/tests/test_resolution.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/tests/test_resolution_bindings.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/tests/test_storage.py +0 -0
- {node_walk-0.4.0 → node_walk-0.5.0}/tests/test_web_server.py +0 -0
|
@@ -3,8 +3,16 @@ name: CI
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
5
|
branches: [ "main", "master" ]
|
|
6
|
+
paths-ignore:
|
|
7
|
+
- "plans/**"
|
|
8
|
+
- "README.md"
|
|
9
|
+
- "CHANGELOG.md"
|
|
6
10
|
pull_request:
|
|
7
11
|
branches: [ "main", "master" ]
|
|
12
|
+
paths-ignore:
|
|
13
|
+
- "plans/**"
|
|
14
|
+
- "README.md"
|
|
15
|
+
- "CHANGELOG.md"
|
|
8
16
|
|
|
9
17
|
jobs:
|
|
10
18
|
test:
|
|
@@ -11,15 +11,43 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
11
11
|
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
+
## [0.5.0] - 2026-08-27
|
|
15
|
+
### Added
|
|
16
|
+
- **Inheritance Traversal in Member Resolution**: Enabled the receiver resolution service to traverse class inheritance (checking both `EXTENDS` and `IMPLEMENTS` edges) when looking up methods, allowing inherited methods to resolve correctly.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
- **Refactoring**: Cleaned up inline imports in the resolution modules (`calls.py` and `receiver.py`) by moving them to the top-level module scope.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
14
23
|
## [0.4.0] - 2026-08-26
|
|
24
|
+
### Added
|
|
25
|
+
- **Chained Receiver Resolution**: Introduced `ReceiverService` and `BindingIndex` to resolve complex, nested receiver chains (e.g. `self.repo.session.get()`) segment by segment.
|
|
26
|
+
- **FastAPI Dependency Injection**: Enhanced parameter and assignment extraction to support FastAPI `Depends(...)` patterns, recording provider references and annotations without creating false call edges to the `Depends` wrapper.
|
|
27
|
+
- **Constructor & Attribute Propagation**: Added logic to trace type contracts established in class initializers (`__init__`) and pass bindings down constructor parameter boundaries.
|
|
15
28
|
|
|
16
29
|
---
|
|
17
30
|
|
|
18
31
|
## [0.3.1] - 2026-08-25
|
|
32
|
+
### Added
|
|
33
|
+
- **Fact-Based Resolution Pipeline**: Shifted the resolution model from direct AST evaluation to a two-phase pipeline using a new `RelationshipFact` SQLite storage layer. Decoupled extraction from graph-edge materialization.
|
|
34
|
+
- **Modular Resolvers**: Implemented specialized fact resolvers:
|
|
35
|
+
- `ImportResolver` for mapping module imports.
|
|
36
|
+
- `BindingResolver` for typed annotations and assignments.
|
|
37
|
+
- `ClassMemberCallResolver` for same-class member resolution.
|
|
38
|
+
- `InFileCallResolver` for local file calls.
|
|
39
|
+
- `ConstructorCallResolver` to map constructor invocations to `__init__` methods.
|
|
40
|
+
- `CrossFileCallResolver` for cross-file call resolution.
|
|
41
|
+
- `InheritanceResolver` for resolving inheritance relationships.
|
|
42
|
+
|
|
43
|
+
### Changed
|
|
44
|
+
- **CI/CD Security**: Migrated PyPI deployment workflow to utilize PyPI Trusted Publishers (environments) and GitHub App authentication.
|
|
19
45
|
|
|
20
46
|
---
|
|
21
47
|
|
|
22
48
|
## [0.3.0] - 2026-08-23
|
|
49
|
+
### Added
|
|
50
|
+
- **Automated Releases**: Implemented hatch-vcs for automatic versioning. Configured automated tagging, release workflow, and package publication to PyPI.
|
|
23
51
|
|
|
24
52
|
---
|
|
25
53
|
|
|
@@ -4,6 +4,7 @@ from node_walk.ir.enums import FactStatus, FactType, SymbolKind
|
|
|
4
4
|
from node_walk.ir.models import RelationshipFact, Symbol
|
|
5
5
|
from node_walk.storage.base import GraphStore
|
|
6
6
|
from node_walk.resolution.base import FactResolver, ResolutionResult
|
|
7
|
+
from node_walk.resolution.receiver import BindingIndex, ReceiverService
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
_BUILTINS = {
|
|
@@ -220,7 +221,6 @@ class CrossFileCallResolver(FactResolver):
|
|
|
220
221
|
return "CrossFileCallResolver"
|
|
221
222
|
|
|
222
223
|
def run(self, store: GraphStore, facts: list[RelationshipFact]) -> int:
|
|
223
|
-
from node_walk.resolution.receiver import BindingIndex, ReceiverService
|
|
224
224
|
self._index = BindingIndex(store)
|
|
225
225
|
self._service = ReceiverService(store, self._index)
|
|
226
226
|
return super().run(store, facts)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from dataclasses import dataclass
|
|
2
2
|
from typing import Optional
|
|
3
3
|
|
|
4
|
-
from node_walk.ir.enums import FactStatus, FactType, SymbolKind
|
|
4
|
+
from node_walk.ir.enums import FactStatus, FactType, SymbolKind, RelationshipType
|
|
5
5
|
from node_walk.ir.models import RelationshipFact, Symbol
|
|
6
6
|
from node_walk.storage.base import GraphStore
|
|
7
7
|
|
|
@@ -171,18 +171,39 @@ class ReceiverService:
|
|
|
171
171
|
)
|
|
172
172
|
|
|
173
173
|
def resolve_member(self, receiver_res: ReceiverResolution, member_name: str) -> SymbolResolution | None:
|
|
174
|
+
|
|
174
175
|
receiver_sym = self._store.get_symbol(receiver_res.resolved_symbol_id)
|
|
175
176
|
if not receiver_sym:
|
|
176
177
|
return None
|
|
177
178
|
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
)
|
|
179
|
+
queue = [receiver_sym.id]
|
|
180
|
+
seen = set()
|
|
181
|
+
|
|
182
|
+
while queue:
|
|
183
|
+
current_id = queue.pop(0)
|
|
184
|
+
if current_id in seen:
|
|
185
|
+
continue
|
|
186
|
+
seen.add(current_id)
|
|
187
|
+
|
|
188
|
+
current_sym = self._store.get_symbol(current_id)
|
|
189
|
+
if not current_sym:
|
|
190
|
+
continue
|
|
191
|
+
|
|
192
|
+
target_qname = f"{current_sym.qualified_name}.{member_name}"
|
|
193
|
+
candidates = self._store.find_symbols_by_qualified_name(target_qname)
|
|
194
|
+
if candidates:
|
|
195
|
+
return SymbolResolution(
|
|
196
|
+
resolved_symbol_id=candidates[0].id,
|
|
197
|
+
confidence=receiver_res.confidence,
|
|
198
|
+
diagnostics={"strategy": "member_lookup", "class": current_sym.name}
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
# If not found, check base classes
|
|
202
|
+
extends = self._store.get_relationships_from(current_id, RelationshipType.EXTENDS)
|
|
203
|
+
implements = self._store.get_relationships_from(current_id, RelationshipType.IMPLEMENTS)
|
|
204
|
+
for rel in extends + implements:
|
|
205
|
+
if rel.target_id:
|
|
206
|
+
queue.append(rel.target_id)
|
|
186
207
|
|
|
187
208
|
return None
|
|
188
209
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|