Skip to content

Commit 279c36e

Browse files
committed
feat: add relation API draft
1 parent 3ca4f9c commit 279c36e

File tree

3 files changed

+128
-0
lines changed

3 files changed

+128
-0
lines changed

docs/schemas/draft/relation.md

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Relation API
2+
3+
The Relation API allows finding all call chains (paths) that connect two specific symbols. This is useful for understanding how one part of the system interacts with another, validating architectural dependencies, or impact analysis.
4+
5+
It leverages the [Call Hierarchy API](call_hierarchy.md) to trace paths.
6+
7+
## RelationRequest
8+
9+
| Field | Type | Default | Description |
10+
| :---------- | :-------------------- | :------- | :----------------------------------------- |
11+
| `source` | [`Locate`](locate.md) | Required | The starting symbol for the path search. |
12+
| `target` | [`Locate`](locate.md) | Required | The ending symbol for the path search. |
13+
| `max_depth` | `number` | `10` | Maximum depth to search for connections. |
14+
15+
## RelationResponse
16+
17+
| Field | Type | Description |
18+
| :---------- | :---------------------- | :-------------------------------------------------------------------------- |
19+
| `source` | `CallHierarchyItem` | The resolved source symbol. |
20+
| `target` | `CallHierarchyItem` | The resolved target symbol. |
21+
| `chains` | `CallHierarchyItem[][]` | List of paths connecting source to target. Each path is a sequence of items.|
22+
| `max_depth` | `number` | The maximum depth used for the search. |
23+
24+
## Example Usage
25+
26+
### Scenario 1: How does `handle_request` reach `db.query`?
27+
28+
#### Request
29+
30+
```json
31+
{
32+
"source": {
33+
"file_path": "src/controllers.py",
34+
"scope": {
35+
"symbol_path": ["handle_request"]
36+
}
37+
},
38+
"target": {
39+
"file_path": "src/db.py",
40+
"scope": {
41+
"symbol_path": ["query"]
42+
}
43+
},
44+
"max_depth": 5
45+
}
46+
```
47+
48+
#### Markdown Rendered for LLM
49+
50+
```markdown
51+
# Relation: `handle_request` → `query`
52+
53+
Found 2 call chain(s):
54+
55+
### Chain 1
56+
1. **handle_request** (`Function`) - `src/controllers.py`
57+
2. **UserService.get_user** (`Method`) - `src/services/user.py`
58+
3. **db.query** (`Function`) - `src/db.py`
59+
60+
### Chain 2
61+
1. **handle_request** (`Function`) - `src/controllers.py`
62+
2. **AuthService.validate_token** (`Method`) - `src/services/auth.py`
63+
3. **SessionManager.get_session** (`Method`) - `src/services/session.py`
64+
4. **db.query** (`Function`) - `src/db.py`
65+
```

src/lsap_schema/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@
4646
RenameResponse,
4747
)
4848

49+
# Relation
50+
from .draft.relation import (
51+
RelationRequest,
52+
RelationResponse,
53+
)
54+
4955
# Type hierarchy
5056
from .draft.type_hierarchy import (
5157
TypeEdge,
@@ -162,6 +168,9 @@
162168
"RenameFileChange",
163169
"RenameRequest",
164170
"RenameResponse",
171+
# Relation
172+
"RelationRequest",
173+
"RelationResponse",
165174
# Symbol
166175
"SymbolRequest",
167176
"SymbolResponse",

src/lsap_schema/draft/relation.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
from typing import Final
2+
3+
from pydantic import ConfigDict
4+
5+
from lsap_schema.abc import Request, Response
6+
from lsap_schema.draft.call_hierarchy import CallHierarchyItem
7+
from lsap_schema.locate import Locate
8+
9+
10+
class RelationRequest(Request):
11+
"""
12+
Finds call chains connecting two symbols.
13+
14+
Uses call hierarchy to trace paths from source to target.
15+
"""
16+
17+
source: Locate
18+
target: Locate
19+
20+
max_depth: int = 10
21+
"""Maximum depth to search for connections"""
22+
23+
24+
markdown_template: Final = """
25+
# Relation: `{{ source.name }}` → `{{ target.name }}`
26+
27+
{% if chains.size > 0 %}
28+
Found {{ chains | size }} call chain(s):
29+
30+
{% for chain in chains %}
31+
### Chain {{ forloop.index }}
32+
{% for item in chain %}
33+
{{ forloop.index }}. **{{ item.name }}** (`{{ item.kind }}`) - `{{ item.file_path }}`
34+
{% endfor %}
35+
{% endfor %}
36+
{% else %}
37+
No connection found between `{{ source.name }}` and `{{ target.name }}` (depth: {{ max_depth }}).
38+
{% endif %}
39+
"""
40+
41+
42+
class RelationResponse(Response):
43+
source: CallHierarchyItem
44+
target: CallHierarchyItem
45+
chains: list[list[CallHierarchyItem]]
46+
"""List of paths, where each path is a sequence of items from source to target."""
47+
48+
max_depth: int
49+
50+
model_config = ConfigDict(
51+
json_schema_extra={
52+
"markdown": markdown_template,
53+
}
54+
)

0 commit comments

Comments
 (0)