aja-codeintel 0.1.2__tar.gz → 0.1.3__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 (80) hide show
  1. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/PKG-INFO +1 -1
  2. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/aja_codeintel.egg-info/PKG-INFO +1 -1
  3. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/aja_codeintel.egg-info/SOURCES.txt +1 -0
  4. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/project/__init__.py +3 -1
  5. aja_codeintel-0.1.3/codeintel_cli/commands/project/types_cmd.py +351 -0
  6. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/pyproject.toml +1 -1
  7. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/LICENSE +0 -0
  8. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/README.md +0 -0
  9. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/aja_codeintel.egg-info/dependency_links.txt +0 -0
  10. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/aja_codeintel.egg-info/entry_points.txt +0 -0
  11. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/aja_codeintel.egg-info/requires.txt +0 -0
  12. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/aja_codeintel.egg-info/top_level.txt +0 -0
  13. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/__init__.py +0 -0
  14. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/__main__.py +0 -0
  15. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/cli.py +0 -0
  16. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/__init__.py +0 -0
  17. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/graph/__init__.py +0 -0
  18. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/graph/deps_cmd.py +0 -0
  19. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/graph/related_cmd.py +0 -0
  20. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/graph/relsymbols_cmd.py +0 -0
  21. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/graph/reverse_related_cmd.py +0 -0
  22. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/nav/__init__.py +0 -0
  23. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/nav/copy_cmd.py +0 -0
  24. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/nav/open_cmd.py +0 -0
  25. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/nav/where_cmd.py +0 -0
  26. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/project/context_cmd.py +0 -0
  27. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/project/endpoints_cmd.py +0 -0
  28. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/project/folder_cmd.py +0 -0
  29. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/project/imports_cmd.py +0 -0
  30. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/project/models_cmd.py +0 -0
  31. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/project/modeltree_cmd.py +0 -0
  32. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/project/new.py +0 -0
  33. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/project/resolve_cmd.py +0 -0
  34. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/project/scan_cmd.py +0 -0
  35. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/project/servicemap_cmd.py +0 -0
  36. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/project/tree_cmd.py +0 -0
  37. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/commands/project/version_cmd.py +0 -0
  38. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/context/java_context.py +0 -0
  39. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/context/java_rel.py +0 -0
  40. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/context/java_service.py +0 -0
  41. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/context/python_context.py +0 -0
  42. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/context/python_rel.py +0 -0
  43. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/context/python_service.py +0 -0
  44. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/core/fuzzy.py +0 -0
  45. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/core/opener.py +0 -0
  46. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/core/project.py +0 -0
  47. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/core/resolve_folder.py +0 -0
  48. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/core/resolve_model_target.py +0 -0
  49. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/core/resolve_target.py +0 -0
  50. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/core/timing.py +0 -0
  51. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/core/where.py +0 -0
  52. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/db/__init__.py +0 -0
  53. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/db/cache.py +0 -0
  54. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/db/operations.py +0 -0
  55. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/db/schema.py +0 -0
  56. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/endpoints/__init__.py +0 -0
  57. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/endpoints/java_spring.py +0 -0
  58. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/endpoints/models.py +0 -0
  59. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/endpoints/python_web.py +0 -0
  60. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/endpoints/scan.py +0 -0
  61. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/errors.py +0 -0
  62. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/graph/__init__.py +0 -0
  63. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/graph/builder.py +0 -0
  64. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/graph/query.py +0 -0
  65. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/graph/traverse.py +0 -0
  66. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/lang/__init__.py +0 -0
  67. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/lang/java/__init__.py +0 -0
  68. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/lang/java/engine.py +0 -0
  69. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/lang/java/models.py +0 -0
  70. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/lang/java/resolve.py +0 -0
  71. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/lang/python/__init__.py +0 -0
  72. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/lang/python/engine.py +0 -0
  73. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/lang/python/models.py +0 -0
  74. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/lang/router.py +0 -0
  75. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/parser/imports.py +0 -0
  76. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/parser/resolve.py +0 -0
  77. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/parser/symbols.py +0 -0
  78. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/scanner/__init__.py +0 -0
  79. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/codeintel_cli/scanner/scanner.py +0 -0
  80. {aja_codeintel-0.1.2 → aja_codeintel-0.1.3}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aja-codeintel
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: CodeIntel CLI tool
5
5
  Author: Your Name
6
6
  License: MIT License
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: aja-codeintel
3
- Version: 0.1.2
3
+ Version: 0.1.3
4
4
  Summary: CodeIntel CLI tool
5
5
  Author: Your Name
6
6
  License: MIT License
@@ -33,6 +33,7 @@ codeintel_cli/commands/project/resolve_cmd.py
33
33
  codeintel_cli/commands/project/scan_cmd.py
34
34
  codeintel_cli/commands/project/servicemap_cmd.py
35
35
  codeintel_cli/commands/project/tree_cmd.py
36
+ codeintel_cli/commands/project/types_cmd.py
36
37
  codeintel_cli/commands/project/version_cmd.py
37
38
  codeintel_cli/context/java_context.py
38
39
  codeintel_cli/context/java_rel.py
@@ -12,6 +12,7 @@ from .modeltree_cmd import register_modeltree
12
12
  from .models_cmd import register_models
13
13
  from .servicemap_cmd import register_servicemap
14
14
  from .endpoints_cmd import register_endpoints
15
+ from .types_cmd import register_types_command
15
16
 
16
17
  def register_project_commands(app: typer.Typer) -> None:
17
18
  register_scan(app)
@@ -24,4 +25,5 @@ def register_project_commands(app: typer.Typer) -> None:
24
25
  register_modeltree(app)
25
26
  register_models(app)
26
27
  register_servicemap(app)
27
- register_endpoints(app)
28
+ register_endpoints(app)
29
+ register_types_command(app)
@@ -0,0 +1,351 @@
1
+ from __future__ import annotations
2
+
3
+ from pathlib import Path
4
+ from typing import Iterable, Optional, Tuple, Any
5
+ import re
6
+ import typer
7
+
8
+ IGNORE_DIRS = {
9
+ ".git", ".idea", ".vscode", ".mvn",
10
+ "__pycache__", ".pytest_cache", ".ruff_cache", ".tox",
11
+ ".venv", "venv", "env",
12
+ "node_modules", "dist", "build", "out", "target", ".gradle",
13
+ }
14
+
15
+ PY_MARKERS = {"dto", "schema", "schemas", "model", "models", "types"}
16
+
17
+ REQ_KEYS = ("request", "create", "update", "input", "payload", "command")
18
+ RES_KEYS = ("response", "result", "output", "view")
19
+
20
+
21
+ # ----------------- file walking -----------------
22
+ def _walk_files(root: Path) -> Iterable[Path]:
23
+ stack = [root]
24
+ while stack:
25
+ cur = stack.pop()
26
+ try:
27
+ for child in cur.iterdir():
28
+ if child.is_dir():
29
+ if child.name not in IGNORE_DIRS:
30
+ stack.append(child)
31
+ else:
32
+ yield child
33
+ except (PermissionError, FileNotFoundError):
34
+ continue
35
+
36
+
37
+ def _is_java_dto(p: Path) -> bool:
38
+ if p.suffix != ".java":
39
+ return False
40
+ parts = [x.lower() for x in p.parts]
41
+ # include auth/dto and dto/request dto/response etc.
42
+ return "dto" in parts
43
+
44
+
45
+ def _is_python_dto_like(p: Path) -> bool:
46
+ if p.suffix != ".py":
47
+ return False
48
+ parts = {part.lower() for part in p.parts}
49
+ return any(m in parts for m in PY_MARKERS)
50
+
51
+
52
+ def _rel(p: Path, root: Path) -> str:
53
+ try:
54
+ return str(p.relative_to(root))
55
+ except ValueError:
56
+ return str(p)
57
+
58
+
59
+ def _read_text_limited(p: Path, max_kb: int = 256) -> str:
60
+ try:
61
+ raw = p.read_bytes()
62
+ except Exception:
63
+ return ""
64
+ raw = raw[: max_kb * 1024]
65
+ return raw.decode("utf-8", errors="replace")
66
+
67
+
68
+ # ----------------- classification -----------------
69
+ def _classify_java(rel_path: str, type_name: str) -> str:
70
+ r = rel_path.lower().replace("\\", "/")
71
+ n = type_name.lower()
72
+
73
+ # folder-based classification is most reliable in your repo
74
+ if "/dto/request/" in r or r.endswith("/request") or "/request/" in r:
75
+ return "request"
76
+ if "/dto/response/" in r or r.endswith("/response") or "/response/" in r:
77
+ return "response"
78
+
79
+ # name heuristics as fallback
80
+ if any(k in n for k in REQ_KEYS):
81
+ return "request"
82
+ if any(k in n for k in RES_KEYS) or "response" in n:
83
+ return "response"
84
+ return "other"
85
+
86
+
87
+ # ----------------- java parsing -----------------
88
+ _record_re = re.compile(
89
+ r"\brecord\s+([A-Za-z_][A-Za-z0-9_]*)\s*\((.*?)\)\s*\{",
90
+ re.S,
91
+ )
92
+
93
+ _class_re = re.compile(
94
+ r"\b(class|record)\s+([A-Za-z_][A-Za-z0-9_]*)\b"
95
+ )
96
+
97
+ _field_re = re.compile(
98
+ # optional annotations lines handled separately; this matches actual field line
99
+ r"^\s*(public|protected|private)?\s*(static\s+)?(final\s+)?([A-Za-z_][\w\<\>\[\]\., ?]+)\s+([A-Za-z_]\w*)\s*(=.*)?;",
100
+ re.M,
101
+ )
102
+
103
+ _annotation_token_re = re.compile(r"^@\w+(\(.*\))?$")
104
+
105
+
106
+ def _strip_java_annotations_from_type(type_tokens: list[str]) -> list[str]:
107
+ # remove leading annotation tokens like @NotBlank, @Email, @Size(...)
108
+ out = []
109
+ for t in type_tokens:
110
+ if _annotation_token_re.match(t.strip()):
111
+ continue
112
+ out.append(t)
113
+ return out
114
+
115
+
116
+ def _parse_java_record(src: str) -> Optional[Tuple[str, list[str]]]:
117
+ m = _record_re.search(src)
118
+ if not m:
119
+ return None
120
+ name = m.group(1)
121
+ params = m.group(2).strip()
122
+ if not params:
123
+ return (name, [])
124
+
125
+ # split by commas (naive but ok for typical DTO params)
126
+ parts = []
127
+ buf = []
128
+ depth_angle = 0
129
+ depth_paren = 0
130
+ for ch in params:
131
+ if ch == "<":
132
+ depth_angle += 1
133
+ elif ch == ">":
134
+ depth_angle = max(0, depth_angle - 1)
135
+ elif ch == "(":
136
+ depth_paren += 1
137
+ elif ch == ")":
138
+ depth_paren = max(0, depth_paren - 1)
139
+
140
+ if ch == "," and depth_angle == 0 and depth_paren == 0:
141
+ parts.append("".join(buf).strip())
142
+ buf = []
143
+ else:
144
+ buf.append(ch)
145
+ if buf:
146
+ parts.append("".join(buf).strip())
147
+
148
+ fields: list[str] = []
149
+ for part in parts:
150
+ tokens = part.split()
151
+ if len(tokens) >= 2:
152
+ fname = tokens[-1].strip()
153
+ ftype_tokens = _strip_java_annotations_from_type(tokens[:-1])
154
+ ftype = " ".join(ftype_tokens).strip() or "?"
155
+ fields.append(f"{fname}:{ftype}")
156
+ else:
157
+ fields.append(part)
158
+
159
+ return (name, fields)
160
+
161
+
162
+ def _parse_java_class_fields(src: str) -> Optional[Tuple[str, list[str]]]:
163
+ # Find first class name (good enough for DTO files)
164
+ cm = _class_re.search(src)
165
+ if not cm:
166
+ return None
167
+ kind = cm.group(1)
168
+ name = cm.group(2)
169
+ if kind == "record":
170
+ # record handled elsewhere
171
+ return None
172
+
173
+ fields: list[str] = []
174
+ for m in _field_re.finditer(src):
175
+ is_static = m.group(2) is not None
176
+ if is_static:
177
+ continue
178
+
179
+ ftype = (m.group(4) or "").strip()
180
+ fname = (m.group(5) or "").strip()
181
+
182
+ # cleanup type
183
+ ftype = re.sub(r"\s+", " ", ftype)
184
+ ftype = ftype.replace(" ?", "?") # tiny cleanup
185
+
186
+ if fname and ftype:
187
+ fields.append(f"{fname}:{ftype}")
188
+
189
+ # de-duplicate while preserving order
190
+ seen = set()
191
+ uniq = []
192
+ for f in fields:
193
+ if f not in seen:
194
+ seen.add(f)
195
+ uniq.append(f)
196
+
197
+ return (name, uniq)
198
+
199
+
200
+ # ----------------- python parsing (optional, kept) -----------------
201
+ def _parse_python_dataclasses(src: str) -> list[Tuple[str, list[str]]]:
202
+ out: list[Tuple[str, list[str]]] = []
203
+ lines = src.splitlines()
204
+
205
+ i = 0
206
+ while i < len(lines):
207
+ if lines[i].strip().startswith("@dataclass"):
208
+ j = i + 1
209
+ while j < len(lines) and "class " not in lines[j]:
210
+ j += 1
211
+ if j >= len(lines):
212
+ break
213
+ cm = re.match(r"\s*class\s+([A-Za-z_][A-Za-z0-9_]*)\s*[:\(]", lines[j])
214
+ if not cm:
215
+ i = j + 1
216
+ continue
217
+
218
+ name = cm.group(1)
219
+
220
+ k = j + 1
221
+ fields: list[str] = []
222
+ while k < len(lines):
223
+ raw = lines[k]
224
+ if raw.strip() == "":
225
+ k += 1
226
+ continue
227
+ if not raw.startswith(" ") and not raw.startswith("\t"):
228
+ break
229
+
230
+ s = raw.strip()
231
+ fm = re.match(r"([A-Za-z_][A-Za-z0-9_]*)\s*:\s*([^=]+?)(\s*=\s*(.+))?$", s)
232
+ if fm:
233
+ fname = fm.group(1).strip()
234
+ ftype = fm.group(2).strip()
235
+ default = fm.group(4).strip() if fm.group(4) else None
236
+ fields.append(f"{fname}:{ftype}" + (f"={default}" if default else ""))
237
+ k += 1
238
+
239
+ out.append((name, fields))
240
+ i = k
241
+ else:
242
+ i += 1
243
+
244
+ return out
245
+
246
+
247
+ # ----------------- printing -----------------
248
+ def _print_section(title: str) -> None:
249
+ typer.echo("")
250
+ typer.echo(title)
251
+ typer.echo("-" * len(title))
252
+
253
+
254
+ def _fmt_item(name: str, fields: list[str], show_path: bool, rel: str) -> str:
255
+ f = ", ".join(fields) if fields else "(no fields found)"
256
+ return f"• {name}: {f}" + (f" ({rel})" if show_path else "")
257
+
258
+
259
+ def register_types_command(app: typer.Typer) -> None:
260
+ @app.command("types")
261
+ def types_cmd(
262
+ path: str = typer.Argument(".", help="Project root/folder to scan"),
263
+ contains: str = typer.Option("", "-c", "--contains", help="Filter by path substring"),
264
+ max_files: int = typer.Option(500, "-n", "--max-files", help="Max files per language"),
265
+ max_kb: int = typer.Option(256, "--max-kb", help="Max KB to read per file"),
266
+ show_path: bool = typer.Option(False, "--show-path", help="Show source file path"),
267
+ ) -> None:
268
+ root = Path(path).resolve()
269
+ if not root.exists():
270
+ raise typer.BadParameter(f"Path not found: {root}")
271
+
272
+ filt = contains.strip().lower()
273
+
274
+ java_files: list[Path] = []
275
+ py_files: list[Path] = []
276
+
277
+ for f in _walk_files(root):
278
+ rel = _rel(f, root)
279
+ if filt and filt not in rel.lower():
280
+ continue
281
+ if _is_java_dto(f):
282
+ java_files.append(f)
283
+ elif _is_python_dto_like(f):
284
+ py_files.append(f)
285
+
286
+ java_files.sort(key=lambda p: _rel(p, root).lower())
287
+ py_files.sort(key=lambda p: _rel(p, root).lower())
288
+
289
+ typer.echo(f"ROOT: {root}")
290
+ typer.echo(f"Filter: {contains!r}" if contains else "Filter: (none)")
291
+
292
+ # ---- JAVA ----
293
+ java_items: list[dict[str, Any]] = []
294
+ for f in java_files[:max_files]:
295
+ src = _read_text_limited(f, max_kb=max_kb)
296
+ rel = _rel(f, root)
297
+
298
+ parsed = _parse_java_record(src)
299
+ if parsed:
300
+ name, fields = parsed
301
+ kind = _classify_java(rel, name)
302
+ java_items.append({"kind": kind, "name": name, "fields": fields, "path": rel})
303
+ continue
304
+
305
+ parsed2 = _parse_java_class_fields(src)
306
+ if parsed2:
307
+ name, fields = parsed2
308
+ kind = _classify_java(rel, name)
309
+ java_items.append({"kind": kind, "name": name, "fields": fields, "path": rel})
310
+
311
+ # ---- PYTHON ----
312
+ py_items: list[dict[str, Any]] = []
313
+ for f in py_files[:max_files]:
314
+ rel = _rel(f, root)
315
+ if rel.endswith("__init__.py"):
316
+ continue
317
+ src = _read_text_limited(f, max_kb=max_kb)
318
+ for name, fields in _parse_python_dataclasses(src):
319
+ py_items.append({"name": name, "fields": fields, "path": rel})
320
+
321
+ # Print only the sections that exist (clean UX)
322
+ if java_items:
323
+ req = [x for x in java_items if x["kind"] == "request"]
324
+ res = [x for x in java_items if x["kind"] == "response"]
325
+ other = [x for x in java_items if x["kind"] == "other"]
326
+
327
+ _print_section(f"JAVA DTO SUMMARY ({len(java_items)})")
328
+
329
+ if req:
330
+ _print_section(f"WHAT WE SEND (REQUEST) ({len(req)})")
331
+ for x in req:
332
+ typer.echo(_fmt_item(x["name"], x["fields"], show_path, x["path"]))
333
+
334
+ if res:
335
+ _print_section(f"WHAT WE RECEIVE (RESPONSE) ({len(res)})")
336
+ for x in res:
337
+ typer.echo(_fmt_item(x["name"], x["fields"], show_path, x["path"]))
338
+
339
+ if other:
340
+ _print_section(f"OTHER JAVA DTO ({len(other)})")
341
+ for x in other:
342
+ typer.echo(_fmt_item(x["name"], x["fields"], show_path, x["path"]))
343
+
344
+ if py_items:
345
+ _print_section(f"PYTHON DTO/MODEL SUMMARY ({len(py_items)})")
346
+ for x in py_items:
347
+ typer.echo(_fmt_item(x["name"], x["fields"], show_path, x["path"]))
348
+
349
+ if not java_items and not py_items:
350
+ typer.echo("")
351
+ typer.echo("(no DTO-like types found)")
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "aja-codeintel"
3
- version = "0.1.2"
3
+ version = "0.1.3"
4
4
  description = "CodeIntel CLI tool"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
File without changes
File without changes
File without changes