sourcecode 5.5.5__py3-none-any.whl → 5.5.6__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 CHANGED
@@ -4,4 +4,4 @@ ASK Engine is the product. ``ask`` is the canonical CLI command; ``sourcecode``
4
4
  the legacy compatibility alias and the Python/PyPI package name. See
5
5
  docs/PRODUCT_IDENTITY.md (normative)."""
6
6
 
7
- __version__ = "5.5.5"
7
+ __version__ = "5.5.6"
@@ -136,7 +136,7 @@ pipx install sourcecode # isolated install, no venv needed
136
136
 
137
137
  # Verify
138
138
  ask version
139
- # ask 5.5.5
139
+ # ask 5.5.6
140
140
  ```
141
141
 
142
142
  Requires Python 3.9+.
sourcecode/cli.py CHANGED
@@ -6311,9 +6311,8 @@ def impact_cmd(
6311
6311
 
6312
6312
  _enforce_format("impact", format)
6313
6313
 
6314
- from sourcecode.repository_ir import (
6315
- build_repo_ir, find_java_files, compute_blast_radius,
6316
- )
6314
+ from sourcecode.repository_ir import find_java_files, compute_blast_radius
6315
+ from sourcecode.context_graph import ContextGraph
6317
6316
  from sourcecode.output_budget import BUDGET_IMPACT
6318
6317
 
6319
6318
  # Legacy-compat: old syntax was `impact <path> <target>`.
@@ -6366,9 +6365,16 @@ def impact_cmd(
6366
6365
  return
6367
6366
 
6368
6367
  _prog = Progress()
6369
- _prog.start(f"building IR ({len(file_list)} files) for impact analysis")
6368
+ _prog.start(f"building CIR ({len(file_list)} files) for impact analysis")
6370
6369
  try:
6371
- ir = build_repo_ir(file_list, root)
6370
+ # `impact-chain` resolves callers from the canonical IR, whose typed body
6371
+ # facts contribute method-level call edges. Reading the legacy parse-only
6372
+ # IR here made `impact` miss static calls (including locator accessors).
6373
+ from sourcecode import context_cache as _ctxcache
6374
+ try:
6375
+ cir = _ctxcache.shared_cir(root, file_list, progress=_work_sink(_prog))
6376
+ except Exception:
6377
+ cir = ContextGraph.build(file_list, root, progress=_work_sink(_prog)).cir
6372
6378
  finally:
6373
6379
  _prog.finish()
6374
6380
 
@@ -6379,7 +6385,7 @@ def impact_cmd(
6379
6385
  # skipped the budget when writing to a file (C2-2).
6380
6386
  _to_file = output_path is not None
6381
6387
  result = compute_blast_radius(
6382
- ir, target, max_depth=depth, list_limit=0 if _to_file else None, root=root
6388
+ cir._raw_ir, target, max_depth=depth, list_limit=0 if _to_file else None, root=root
6383
6389
  )
6384
6390
  result = _apply_budget(result, BUDGET_IMPACT, label="impact", output_path=output_path)
6385
6391
  if _misread and result.get("resolution") == "not_found":
@@ -3833,8 +3833,6 @@ def _route_annotation_name(sym: SymbolRecord) -> str:
3833
3833
  def _enclosing_class(fqn: str) -> str:
3834
3834
  if "#" in fqn:
3835
3835
  return fqn.split("#")[0]
3836
- if "." in fqn:
3837
- return fqn.rsplit(".", 1)[0]
3838
3836
  return fqn
3839
3837
 
3840
3838
 
@@ -88,42 +88,53 @@ def _from_web_xml(xml_path: Path, relative: str) -> "tuple[list[ServletMapping],
88
88
  text = xml_path.read_text(encoding="utf-8", errors="replace")
89
89
  root = ET.fromstring(text)
90
90
  except Exception:
91
- return [], 0
91
+ # Legacy descriptors can contain constructs ElementTree rejects. Keep the
92
+ # lexical fallback below, including its omission census; returning here
93
+ # made an undeclared live mapping look as though it had never existed.
94
+ root = None
92
95
  classes: "dict[str, str]" = {}
93
- for elem in root.iter():
94
- if _local(elem.tag) != "servlet":
95
- continue
96
- name = _child_text(elem, "servlet-name")
97
- klass = _child_text(elem, "servlet-class")
98
- if name:
99
- classes[name] = klass
96
+ if root is not None:
97
+ for elem in root.iter():
98
+ if _local(elem.tag) != "servlet":
99
+ continue
100
+ name = _child_text(elem, "servlet-name")
101
+ klass = _child_text(elem, "servlet-class")
102
+ if name:
103
+ classes[name] = klass
100
104
  out: "list[ServletMapping]" = []
101
105
  undeclared_servlet_mappings = 0
102
- for elem in root.iter():
103
- if _local(elem.tag) != "servlet-mapping":
104
- continue
105
- name = _child_text(elem, "servlet-name")
106
- if not name or name not in classes:
107
- undeclared_servlet_mappings += sum(
108
- 1 for child in elem.iter()
109
- if _local(child.tag) == "url-pattern" and (child.text or "").strip()
110
- )
111
- continue
112
- for child in elem.iter():
113
- if _local(child.tag) != "url-pattern" or not (child.text or "").strip():
106
+ if root is not None:
107
+ for elem in root.iter():
108
+ if _local(elem.tag) != "servlet-mapping":
114
109
  continue
115
- out.append(ServletMapping(
116
- url_pattern=child.text.strip(),
117
- servlet_name=name,
118
- servlet_class=classes.get(name, ""),
119
- source_file=relative,
120
- source="web.xml",
121
- ))
110
+ name = _child_text(elem, "servlet-name")
111
+ if not name or name not in classes:
112
+ undeclared_servlet_mappings += sum(
113
+ 1 for child in elem.iter()
114
+ if _local(child.tag) == "url-pattern" and (child.text or "").strip()
115
+ )
116
+ continue
117
+ for child in elem.iter():
118
+ if _local(child.tag) != "url-pattern" or not (child.text or "").strip():
119
+ continue
120
+ out.append(ServletMapping(
121
+ url_pattern=child.text.strip(),
122
+ servlet_name=name,
123
+ servlet_class=classes.get(name, ""),
124
+ source_file=relative,
125
+ source="web.xml",
126
+ ))
122
127
  # Keep a tolerant lexical fallback for descriptors containing legacy XML
123
128
  # constructs that ElementTree rejects or partially normalizes. Comments are
124
129
  # removed first so commented deployment examples never become live routes.
125
130
  try:
126
131
  active = re.sub(r"<!--.*?-->", "", text, flags=re.DOTALL)
132
+ if root is None:
133
+ for block in re.findall(r"<servlet\b[^>]*>(.*?)</servlet>", active, re.DOTALL | re.IGNORECASE):
134
+ name_match = re.search(r"<servlet-name\b[^>]*>\s*([^<]+?)\s*</servlet-name>", block, re.DOTALL | re.IGNORECASE)
135
+ class_match = re.search(r"<servlet-class\b[^>]*>\s*([^<]+?)\s*</servlet-class>", block, re.DOTALL | re.IGNORECASE)
136
+ if name_match:
137
+ classes[name_match.group(1).strip()] = class_match.group(1).strip() if class_match else ""
127
138
  for block in re.findall(r"<servlet-mapping\b[^>]*>(.*?)</servlet-mapping>", active, re.DOTALL | re.IGNORECASE):
128
139
  name_match = re.search(r"<servlet-name\b[^>]*>\s*([^<]+?)\s*</servlet-name>", block, re.DOTALL | re.IGNORECASE)
129
140
  pattern_match = re.search(r"<url-pattern\b[^>]*>\s*([^<]+?)\s*</url-pattern>", block, re.DOTALL | re.IGNORECASE)
@@ -131,6 +142,8 @@ def _from_web_xml(xml_path: Path, relative: str) -> "tuple[list[ServletMapping],
131
142
  continue
132
143
  servlet_name = name_match.group(1).strip() if name_match else ""
133
144
  if not servlet_name or servlet_name not in classes:
145
+ if root is None:
146
+ undeclared_servlet_mappings += 1
134
147
  continue
135
148
  candidate = ServletMapping(
136
149
  url_pattern=pattern_match.group(1).strip(),
sourcecode/timeline.py CHANGED
@@ -211,7 +211,12 @@ class Sample:
211
211
 
212
212
  def _git(repo: Path, *args: str) -> subprocess.CompletedProcess:
213
213
  return subprocess.run(
214
- ["git", "-C", str(repo), *args], capture_output=True, text=True, check=False,
214
+ ["git", "-C", str(repo), "-c", "i18n.logOutputEncoding=utf-8", *args],
215
+ capture_output=True,
216
+ text=True,
217
+ encoding="utf-8",
218
+ errors="replace",
219
+ check=False,
215
220
  )
216
221
 
217
222
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sourcecode
3
- Version: 5.5.5
3
+ Version: 5.5.6
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
@@ -42,7 +42,7 @@ Description-Content-Type: text/markdown
42
42
 
43
43
  **Context · Impact · Migration · Architecture · Review — everything from one structural model.**
44
44
 
45
- ![Version](https://img.shields.io/badge/version-5.5.5-blue)
45
+ ![Version](https://img.shields.io/badge/version-5.5.6-blue)
46
46
  ![Python](https://img.shields.io/badge/python-3.9%2B-green)
47
47
 
48
48
  > **ASK Engine** is the product. The CLI command is **`ask`**. The legacy **`sourcecode`**
@@ -126,7 +126,7 @@ brew tap haroundominique/sourcecode && brew install sourcecode
126
126
  # pip / pipx
127
127
  pipx install sourcecode # or: pip install sourcecode
128
128
 
129
- ask version # ask 5.5.5 — and, on a build that has aged,
129
+ ask version # ask 5.5.6 — and, on a build that has aged,
130
130
  # how many releases have probably shipped since
131
131
  ```
132
132
 
@@ -1,4 +1,4 @@
1
- sourcecode/__init__.py,sha256=LWoy6uySGMfIcuMSAGcCF4LHEF2d_DbNo4PrVl8kous,308
1
+ sourcecode/__init__.py,sha256=ubmZr-Z6Jw6Sga5f4aR5nwzDbDnqraRBMhiWruqW8WE,308
2
2
  sourcecode/adaptive_scanner.py,sha256=yJBKjNpkY6bpueYJ2YnRezen3sYZDecEt7WaaNWdqug,9466
3
3
  sourcecode/archetype.py,sha256=CZvRLpkHot_D8D3JFQVorr-EHDJyh0BbS7RnSTqBigM,40499
4
4
  sourcecode/architectural_baseline.py,sha256=4GiMVBLJVHvRKSWQGf2ZVurI1-R0qk5pmaevgvGSgVA,26325
@@ -19,7 +19,7 @@ sourcecode/chain_rules.py,sha256=Bi6UHfgd-GxWswmnHRcPz5jdbAuqka3Zkz_P-MTvqhw,127
19
19
  sourcecode/change_plan.py,sha256=aX1mp2XnlDN-8R2BcTiu8HlkDwQ_4fN1ZLckj0VMXHM,9945
20
20
  sourcecode/cir_graphs.py,sha256=9G0HHj1kw2325IDyzo2OpX73BNswEckecf4MZUXB4JM,12078
21
21
  sourcecode/classifier.py,sha256=JBzPwSSrDG-tUHAbcKB678HRbjLpD-ohzbzzO62mgpo,20114
22
- sourcecode/cli.py,sha256=Lq6Kbunzj01R5pbcDbrF8lMslaTpc4JbrLyVozCsstA,650907
22
+ sourcecode/cli.py,sha256=gpy9sUfNA5Zz2E7Xf9j95W2axCLLbtuQpZUGMym7a1E,651407
23
23
  sourcecode/client_calls.py,sha256=5_sBfFVXi6RgGiyWrlJKH4x4EF21do6gKlAOuFCKAoA,17709
24
24
  sourcecode/code_notes_analyzer.py,sha256=EJemNCNc9Dn-1RZYu-aNbK0ELzmsyC4s6FdHi3XyNEI,9392
25
25
  sourcecode/compare.py,sha256=2GdDy0qkDSgmkkpgvoCHitoLj3mt30EeFgJ8PGEXJng,14712
@@ -106,7 +106,7 @@ sourcecode/relevance_scorer.py,sha256=0AgEt4KrV73nioMqBgjhGjtY7L2C7L7cSyKtj3IKcr
106
106
  sourcecode/remedies.py,sha256=V2_cD4pLq8bKRkzF-3RGFoiu1xWYZS384WDVp1MrlZw,10225
107
107
  sourcecode/rename_refactor.py,sha256=h6dNFlB9aZ_3q6heeHBkgXQeXaT03nvPSsYH6P8qxFg,12965
108
108
  sourcecode/repo_classifier.py,sha256=FG1vaWKdWXsWdl-S8hjVMiTqcwgaRXkDyvK4rPcOGtQ,22681
109
- sourcecode/repository_ir.py,sha256=nSStGh9z8uHSTj92IJp85Y1J8NDGqlY59KtEsgHThqY,388812
109
+ sourcecode/repository_ir.py,sha256=OIIDN-Vt_SeoPj7YZltZtCppDs5XJ1idJPhTLWphK90,388756
110
110
  sourcecode/ris.py,sha256=Xbx34dkJI_uXil9xsgw-fA_Apcm4nbnTjQgFm66dP1g,27489
111
111
  sourcecode/risk.py,sha256=u2V7nG5yGW8VV4sFDSgFkZqdI6ltmilWhlQwlIH7d2o,82660
112
112
  sourcecode/rule_catalog.py,sha256=pTkgkQZ1u7atB3fkQJ9BPWo8lNiamvEuRN7MtRgle0c,5263
@@ -125,7 +125,7 @@ sourcecode/semantic_impact_engine.py,sha256=t09IirGC3JjQDy33JZd1_WKzQVKXkoNl3-XE
125
125
  sourcecode/semantic_integration_engine.py,sha256=7a0WqAInOv39f0Yr_94TYo_JP_8QpeI9KGaknpzAyQU,18899
126
126
  sourcecode/semantic_services.py,sha256=nbUuPv-F01USTt_9CHT8iy_ucCIw3fz4W3Aquea_pd4,10782
127
127
  sourcecode/serializer.py,sha256=cK4I3WzX0H-oBPbqzBsUBRux5GcYmH_yPDQwxvkf8yQ,141598
128
- sourcecode/servlet_surface.py,sha256=1ZB76G5PrIGqmRAO8rEd20SMYoexZ5t01v82HtHLSXo,12481
128
+ sourcecode/servlet_surface.py,sha256=CeiebkxLXKojUQxIf7HV7tdQAwLM32ggDUwBnVQIjdo,13499
129
129
  sourcecode/source_text.py,sha256=R52gmSljz7L6YVPbixv5W-LOZ5eKUVvSUP3S-QH_IWc,9047
130
130
  sourcecode/spring_event_topology.py,sha256=5_ON_21Le5zbG-1GRc5GLIi5HJfy_QjcXLVPC5WeUGQ,18055
131
131
  sourcecode/spring_findings.py,sha256=cW6NiQAFUM9mDYPitJr6MrQg--YBI41LxrSEMI9aeIQ,25272
@@ -142,7 +142,7 @@ sourcecode/target_admission.py,sha256=wFZ4pzlxhiF6Q6s2lEAZEzcCfj1Y6xNvujjt8MdO0Q
142
142
  sourcecode/test_gap_ranking.py,sha256=hl-tTyQUXZGJycG1b6npbLeE_DaVHaOsvPwG9qqC5y8,15711
143
143
  sourcecode/test_sources.py,sha256=KM88qbMfLDmUV5X2nA83LjYz8A2ipj4A_2u2FhZx8gc,9440
144
144
  sourcecode/text_input.py,sha256=3pL8DxR_DMI3ece-B70DnppvrEaLh4R17Pp8dK9G_hc,3596
145
- sourcecode/timeline.py,sha256=fU8UiHgf0qO2OsT-xe77tWeRJgp6ov55ZyXqnEGmd_E,17590
145
+ sourcecode/timeline.py,sha256=mIEzaIylhtu2PBoqqz2iI4K_OxZf8fx9-Lf-Zj6QFXM,17704
146
146
  sourcecode/token_estimate.py,sha256=G-ivzIJfVq5TLQN04dC0WK4LZJjWVYL54Ebcxe4fJ7M,9268
147
147
  sourcecode/tree_utils.py,sha256=8GAkIfQAsvtEudIeW1l4ooH_oRtrWR8cpJQJsEa_Pfw,2093
148
148
  sourcecode/type_usage_surface.py,sha256=51IrKRQoIoRnlsiDjHnqpJBn2rc6E59aRhgS0HTzAF0,4428
@@ -214,9 +214,9 @@ sourcecode/telemetry/events.py,sha256=4_yeO58U-Cwc1Qb27VB0_EjhmroY0k91n3_VGxeALB
214
214
  sourcecode/telemetry/filters.py,sha256=RzxauTz8HliO4BllQnXEXc7zTeqdCZi5MgqGEDuW7OQ,6570
215
215
  sourcecode/telemetry/transport.py,sha256=4gGHsq0WeY9VywEZXA3vUxykfiYnw9uuqfjAAec7F8o,1681
216
216
  sourcecode/_docs/DEFECT-LEDGER.md,sha256=5SxWnKt6p5ZRmx-WsFhIlMfe7-e5fLF0QRa9lAmzYug,499071
217
- sourcecode/_docs/USER_GUIDE.md,sha256=ykjudytfe1VLgGJQAcs36wkXsEO3N-QJY2js1cJc7y0,79837
218
- sourcecode-5.5.5.dist-info/METADATA,sha256=bMkQLLoD1zYBemJ5ZJpHyy9xIurRVdVOTCP20jSLN6I,47104
219
- sourcecode-5.5.5.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
220
- sourcecode-5.5.5.dist-info/entry_points.txt,sha256=-JEAdChrK5We51kZcb7OaDcyil-dHBjBPL-NhuO-QY8,89
221
- sourcecode-5.5.5.dist-info/licenses/LICENSE,sha256=7DdHrU9Z_3e7dSvq4ISijZNjnuHo5NIHNiHDouMQ9JU,10491
222
- sourcecode-5.5.5.dist-info/RECORD,,
217
+ sourcecode/_docs/USER_GUIDE.md,sha256=3qnsv3J0_xObxpztohrNk2heGlrRl_0z3k-1I0gS5s8,79837
218
+ sourcecode-5.5.6.dist-info/METADATA,sha256=8U54F5TzqQ4e0_inhak4Fjx_ajsBrFyXyFO3fsHr_Z8,47104
219
+ sourcecode-5.5.6.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
220
+ sourcecode-5.5.6.dist-info/entry_points.txt,sha256=-JEAdChrK5We51kZcb7OaDcyil-dHBjBPL-NhuO-QY8,89
221
+ sourcecode-5.5.6.dist-info/licenses/LICENSE,sha256=7DdHrU9Z_3e7dSvq4ISijZNjnuHo5NIHNiHDouMQ9JU,10491
222
+ sourcecode-5.5.6.dist-info/RECORD,,