sourcecode 1.58.0__py3-none-any.whl → 1.59.0__py3-none-any.whl
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.
- sourcecode/__init__.py +1 -1
- sourcecode/repository_ir.py +106 -2
- {sourcecode-1.58.0.dist-info → sourcecode-1.59.0.dist-info}/METADATA +3 -3
- {sourcecode-1.58.0.dist-info → sourcecode-1.59.0.dist-info}/RECORD +7 -7
- {sourcecode-1.58.0.dist-info → sourcecode-1.59.0.dist-info}/WHEEL +0 -0
- {sourcecode-1.58.0.dist-info → sourcecode-1.59.0.dist-info}/entry_points.txt +0 -0
- {sourcecode-1.58.0.dist-info → sourcecode-1.59.0.dist-info}/licenses/LICENSE +0 -0
sourcecode/__init__.py
CHANGED
sourcecode/repository_ir.py
CHANGED
|
@@ -347,12 +347,17 @@ _SPRING_OTHER: frozenset[str] = frozenset({
|
|
|
347
347
|
"@MatrixParam", "@CookieParam", "@Context",
|
|
348
348
|
})
|
|
349
349
|
|
|
350
|
-
|
|
350
|
+
# Optional generic type args between the event class name and its constructor
|
|
351
|
+
# parens — diamond `<>` or explicit `<Order>` / `<Map<String,Integer>>`.
|
|
352
|
+
# Required so `publishEvent(new SaveServiceEvent<>(obj))` (generic event wrappers,
|
|
353
|
+
# e.g. OpenMRS *ServiceEvent family) is recognised as a publisher edge.
|
|
354
|
+
_GENERIC_ARGS = r'(?:<[^<>;{}()]*(?:<[^<>;{}()]*>[^<>;{}()]*)*>)?'
|
|
355
|
+
_PUBLISH_EVENT_RE = re.compile(r'\.publishEvent\s*\(\s*new\s+(\w+)\s*' + _GENERIC_ARGS + r'\s*[(\{]')
|
|
351
356
|
|
|
352
357
|
# Two-step publish: SomeEvent var = new SomeEvent(...); publisher.publishEvent(var)
|
|
353
358
|
# Used when event is created before passing to publishEvent (common pattern).
|
|
354
359
|
_PUBLISH_EVENT_CALL_RE = re.compile(r'\.publishEvent\s*\(')
|
|
355
|
-
_NEW_EVENT_INSTANTIATION_RE = re.compile(r'\bnew\s+(\w+Event)\s*[\({]')
|
|
360
|
+
_NEW_EVENT_INSTANTIATION_RE = re.compile(r'\bnew\s+(\w+Event)\s*' + _GENERIC_ARGS + r'\s*[\({]')
|
|
356
361
|
|
|
357
362
|
# Keycloak SPI event fire pattern: XxxEvent.fire(session, ...)
|
|
358
363
|
_FIRE_EVENT_RE = re.compile(r'\b(\w+Event)\.fire\s*\(')
|
|
@@ -1122,6 +1127,102 @@ def _build_same_package_map(symbols: list[SymbolRecord]) -> dict[str, dict[str,
|
|
|
1122
1127
|
return result
|
|
1123
1128
|
|
|
1124
1129
|
|
|
1130
|
+
# Reserved words that read like calls (`if (`, `for (`, …). Can never be sibling
|
|
1131
|
+
# method names (Java reserves them), but guard the intra-class scan anyway.
|
|
1132
|
+
_CALL_KEYWORDS: frozenset[str] = frozenset({
|
|
1133
|
+
"if", "for", "while", "switch", "catch", "return", "synchronized",
|
|
1134
|
+
"new", "super", "this", "assert",
|
|
1135
|
+
})
|
|
1136
|
+
|
|
1137
|
+
|
|
1138
|
+
def _method_body(raw_lines: list[str], start_idx: int) -> str:
|
|
1139
|
+
"""Source text of the method/constructor declared at raw_lines[start_idx],
|
|
1140
|
+
from its first '{' to the matching '}' (brace-matched, string/char aware).
|
|
1141
|
+
|
|
1142
|
+
The signature prefix before '{' is dropped so the method's own name is not
|
|
1143
|
+
scanned as a call site. Returns "" for a bodyless declaration (abstract /
|
|
1144
|
+
interface method terminated by ';' before any '{').
|
|
1145
|
+
"""
|
|
1146
|
+
depth = 0
|
|
1147
|
+
started = False
|
|
1148
|
+
out: list[str] = []
|
|
1149
|
+
for i in range(start_idx, len(raw_lines)):
|
|
1150
|
+
line = raw_lines[i]
|
|
1151
|
+
if not started:
|
|
1152
|
+
if "{" in line:
|
|
1153
|
+
started = True
|
|
1154
|
+
line = line[line.index("{"):]
|
|
1155
|
+
elif ";" in line:
|
|
1156
|
+
return "" # bodyless declaration
|
|
1157
|
+
else:
|
|
1158
|
+
continue # multi-line signature continuation
|
|
1159
|
+
out.append(line)
|
|
1160
|
+
depth += _count_net_braces(line)
|
|
1161
|
+
if depth <= 0:
|
|
1162
|
+
break
|
|
1163
|
+
return "\n".join(out)
|
|
1164
|
+
|
|
1165
|
+
|
|
1166
|
+
def _intra_class_call_edges(symbols: list[SymbolRecord], source: str) -> list[RelationEdge]:
|
|
1167
|
+
"""Method-level `calls` edges for intra-class invocations.
|
|
1168
|
+
|
|
1169
|
+
`discontinueOrder(){ stopOrder(...); }` →
|
|
1170
|
+
OrderServiceImpl#discontinueOrder --calls--> OrderServiceImpl#stopOrder.
|
|
1171
|
+
|
|
1172
|
+
Class-level call scans miss method-to-method calls within a single class, so
|
|
1173
|
+
impact-chain on a private/helper method (e.g. OrderServiceImpl#stopOrder) found
|
|
1174
|
+
zero method-level callers and degraded to a wrong class-level expansion. Resolves
|
|
1175
|
+
bare `m(...)` and `this.m(...)` calls whose target is a sibling METHOD of the same
|
|
1176
|
+
class. Overloads link to all same-name siblings (arity not resolved by regex).
|
|
1177
|
+
Deterministic, in-source only — no cross-file or runtime inference.
|
|
1178
|
+
"""
|
|
1179
|
+
callers = [s for s in symbols if s.symbol_kind in ("method", "constructor") and s.line]
|
|
1180
|
+
if not callers:
|
|
1181
|
+
return []
|
|
1182
|
+
|
|
1183
|
+
# Per-class sibling index: simple method name → [method FQNs]. Constructors are
|
|
1184
|
+
# not call targets (a `new X(...)` site is a different relation).
|
|
1185
|
+
siblings: dict[str, dict[str, list[str]]] = {}
|
|
1186
|
+
for s in symbols:
|
|
1187
|
+
if s.symbol_kind == "method" and "#" in s.symbol:
|
|
1188
|
+
cls = _enclosing_class(s.symbol)
|
|
1189
|
+
name = s.symbol.rsplit("#", 1)[1]
|
|
1190
|
+
siblings.setdefault(cls, {}).setdefault(name, []).append(s.symbol)
|
|
1191
|
+
if not siblings:
|
|
1192
|
+
return []
|
|
1193
|
+
|
|
1194
|
+
raw_lines = source.splitlines()
|
|
1195
|
+
edges: list[RelationEdge] = []
|
|
1196
|
+
for caller in callers:
|
|
1197
|
+
cls = _enclosing_class(caller.symbol)
|
|
1198
|
+
sib = siblings.get(cls)
|
|
1199
|
+
if not sib:
|
|
1200
|
+
continue
|
|
1201
|
+
body = _method_body(raw_lines, caller.line - 1)
|
|
1202
|
+
if not body:
|
|
1203
|
+
continue
|
|
1204
|
+
body = _STRING_LITERAL_RE.sub('', _strip_java_comments(body))
|
|
1205
|
+
for name, fqns in sib.items():
|
|
1206
|
+
if name in _CALL_KEYWORDS:
|
|
1207
|
+
continue
|
|
1208
|
+
# bare `name(` (not preceded by word char or '.') OR explicit `this.name(`
|
|
1209
|
+
pat = (r'(?<![\w.])' + re.escape(name) + r'\s*\('
|
|
1210
|
+
+ r'|\bthis\s*\.\s*' + re.escape(name) + r'\s*\(')
|
|
1211
|
+
if not re.search(pat, body):
|
|
1212
|
+
continue
|
|
1213
|
+
for tgt in fqns:
|
|
1214
|
+
if tgt == caller.symbol:
|
|
1215
|
+
continue # skip self-recursion self-loop
|
|
1216
|
+
edges.append(RelationEdge(
|
|
1217
|
+
from_symbol=caller.symbol,
|
|
1218
|
+
to_symbol=tgt,
|
|
1219
|
+
type="calls",
|
|
1220
|
+
confidence="medium",
|
|
1221
|
+
evidence={"type": "method_call", "value": f"{name}(...)"},
|
|
1222
|
+
))
|
|
1223
|
+
return edges
|
|
1224
|
+
|
|
1225
|
+
|
|
1125
1226
|
def _build_relations(
|
|
1126
1227
|
symbols: list[SymbolRecord],
|
|
1127
1228
|
raw_imports: list[str],
|
|
@@ -1557,6 +1658,9 @@ def _build_relations(
|
|
|
1557
1658
|
evidence={"type": "method_call", "value": f"{_tgt.split('.')[-1]}.…(…)"},
|
|
1558
1659
|
))
|
|
1559
1660
|
|
|
1661
|
+
# ── Intra-class method calls: EnclosingMethod -> calls -> SameClass#sibling ──
|
|
1662
|
+
edges.extend(_intra_class_call_edges(symbols, source))
|
|
1663
|
+
|
|
1560
1664
|
seen: set[tuple[str, str, str]] = set()
|
|
1561
1665
|
unique: list[RelationEdge] = []
|
|
1562
1666
|
for e in edges:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.59.0
|
|
4
4
|
Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Keywords: agents,ai,codebase,context,developer-tools,llm
|
|
@@ -40,7 +40,7 @@ Description-Content-Type: text/markdown
|
|
|
40
40
|
|
|
41
41
|
**Persistent structural context and ultra-fast repeated analysis for AI coding agents.**
|
|
42
42
|
|
|
43
|
-

|
|
44
44
|

|
|
45
45
|
|
|
46
46
|
---
|
|
@@ -114,7 +114,7 @@ pipx install sourcecode
|
|
|
114
114
|
|
|
115
115
|
```bash
|
|
116
116
|
sourcecode version
|
|
117
|
-
# sourcecode 1.
|
|
117
|
+
# sourcecode 1.59.0
|
|
118
118
|
```
|
|
119
119
|
|
|
120
120
|
---
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
sourcecode/__init__.py,sha256=
|
|
1
|
+
sourcecode/__init__.py,sha256=2epIg2XeTy7k3HoxrmwEPHso7xkeVSRJ3jh1LHHjjkU,103
|
|
2
2
|
sourcecode/adaptive_scanner.py,sha256=XffluXKzJUXrMtjEiAOnSNPZnztdIcts17T9ouHeID0,10521
|
|
3
3
|
sourcecode/architecture_analyzer.py,sha256=liCwQmLgb5vplohy8arjYxs_HOIv5C9MjLh_gY6bc5Q,44115
|
|
4
4
|
sourcecode/architecture_summary.py,sha256=z34_6v7cSwy98cof2UVciGho7SCrZ93tiqMmq5WNzRQ,20405
|
|
@@ -45,7 +45,7 @@ sourcecode/redactor.py,sha256=SB4hwIvg8h-hvcqKcDWaZvA-aSyn-at-BIRwa0tUv5E,3227
|
|
|
45
45
|
sourcecode/relevance_scorer.py,sha256=0AgEt4KrV73nioMqBgjhGjtY7L2C7L7cSyKtj3IKcrw,9408
|
|
46
46
|
sourcecode/rename_refactor.py,sha256=h6dNFlB9aZ_3q6heeHBkgXQeXaT03nvPSsYH6P8qxFg,12965
|
|
47
47
|
sourcecode/repo_classifier.py,sha256=FG1vaWKdWXsWdl-S8hjVMiTqcwgaRXkDyvK4rPcOGtQ,22681
|
|
48
|
-
sourcecode/repository_ir.py,sha256=
|
|
48
|
+
sourcecode/repository_ir.py,sha256=YjpmR-Tdfnep1ryjfCQLjttLoKOcq0_11XbhuomDFX8,218657
|
|
49
49
|
sourcecode/ris.py,sha256=RcqLVwC-doFcKKViYDkCjZLBqf_wzLES7-F6vHEeWzE,20419
|
|
50
50
|
sourcecode/runtime_classifier.py,sha256=uTAD6BDCiBLUZEDRfqk718kM4RTT_vAbfkcOI2_Xx58,18432
|
|
51
51
|
sourcecode/scanner.py,sha256=WdOQ78mMzjR1NjmKTlbxdgwinnCTfAhxCVLBEFQiFHU,8899
|
|
@@ -102,8 +102,8 @@ sourcecode/telemetry/consent.py,sha256=wLMvGNJeSSyZoNkQXpoUioY6mMv4Qdvuw7S9jAEWn
|
|
|
102
102
|
sourcecode/telemetry/events.py,sha256=LtzYfaX9Ilckj5PTvAcTpDa9mLqDsYPDUiDkRa58piY,2580
|
|
103
103
|
sourcecode/telemetry/filters.py,sha256=NHa5T-6DaZduQPFuC34jOqHWQgSizM-Ygq8aZ4j19ng,5834
|
|
104
104
|
sourcecode/telemetry/transport.py,sha256=4gGHsq0WeY9VywEZXA3vUxykfiYnw9uuqfjAAec7F8o,1681
|
|
105
|
-
sourcecode-1.
|
|
106
|
-
sourcecode-1.
|
|
107
|
-
sourcecode-1.
|
|
108
|
-
sourcecode-1.
|
|
109
|
-
sourcecode-1.
|
|
105
|
+
sourcecode-1.59.0.dist-info/METADATA,sha256=Tl_qHFWT-yXKwDto4VaZ_H9xnvBvabtL_oCosI4fn-0,38831
|
|
106
|
+
sourcecode-1.59.0.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
107
|
+
sourcecode-1.59.0.dist-info/entry_points.txt,sha256=ex3F9rmbXeyDIoFQHtkEqTsKSaJow8F0LrVu8XfIktQ,57
|
|
108
|
+
sourcecode-1.59.0.dist-info/licenses/LICENSE,sha256=7DdHrU9Z_3e7dSvq4ISijZNjnuHo5NIHNiHDouMQ9JU,10491
|
|
109
|
+
sourcecode-1.59.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|