tree-sitter-analyzer 1.6.1__py3-none-any.whl → 1.6.2__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.

Potentially problematic release.


This version of tree-sitter-analyzer might be problematic. Click here for more details.

@@ -11,7 +11,7 @@ Architecture:
11
11
  - Data Models: Generic and language-specific code element representations
12
12
  """
13
13
 
14
- __version__ = "1.6.1"
14
+ __version__ = "1.6.2"
15
15
  __author__ = "aisheng.yu"
16
16
  __email__ = "aimasteracc@gmail.com"
17
17
 
@@ -7,6 +7,7 @@ from .base_formatter import BaseTableFormatter
7
7
  from .java_formatter import JavaTableFormatter
8
8
  from .javascript_formatter import JavaScriptTableFormatter
9
9
  from .python_formatter import PythonTableFormatter
10
+ from .typescript_formatter import TypeScriptTableFormatter
10
11
 
11
12
 
12
13
  class TableFormatterFactory:
@@ -17,6 +18,8 @@ class TableFormatterFactory:
17
18
  "javascript": JavaScriptTableFormatter,
18
19
  "js": JavaScriptTableFormatter, # Alias
19
20
  "python": PythonTableFormatter,
21
+ "typescript": TypeScriptTableFormatter,
22
+ "ts": TypeScriptTableFormatter, # Alias
20
23
  }
21
24
 
22
25
  @classmethod
@@ -0,0 +1,432 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ TypeScript-specific table formatter.
4
+
5
+ Provides specialized formatting for TypeScript code analysis results,
6
+ handling TypeScript-specific features like interfaces, type aliases, enums,
7
+ generics, decorators, and modern JavaScript features with type annotations.
8
+ """
9
+
10
+ from typing import Any
11
+
12
+ from .base_formatter import BaseTableFormatter
13
+
14
+
15
+ class TypeScriptTableFormatter(BaseTableFormatter):
16
+ """Table formatter specialized for TypeScript"""
17
+
18
+ def format(self, data: dict[str, Any]) -> str:
19
+ """Format data using the configured format type"""
20
+ return self.format_structure(data)
21
+
22
+ def _format_full_table(self, data: dict[str, Any]) -> str:
23
+ """Full table format for TypeScript"""
24
+ lines = []
25
+
26
+ # Header - TypeScript (module/file based)
27
+ file_path = data.get("file_path", "Unknown")
28
+ file_name = file_path.split("/")[-1].split("\\")[-1]
29
+ module_name = (
30
+ file_name.replace(".ts", "").replace(".tsx", "").replace(".d.ts", "")
31
+ )
32
+
33
+ # Check if this is a module (has exports, classes, interfaces, or functions)
34
+ exports = data.get("exports", [])
35
+ classes = data.get("classes", [])
36
+ interfaces = data.get("interfaces", [])
37
+ functions = data.get("functions", [])
38
+ is_module = len(exports) > 0 or len(classes) > 0 or len(interfaces) > 0 or len(functions) > 0
39
+ is_declaration_file = file_name.endswith(".d.ts")
40
+ is_tsx = file_name.endswith(".tsx")
41
+
42
+ if is_declaration_file:
43
+ lines.append(f"# Declaration File: {module_name}")
44
+ elif is_tsx:
45
+ lines.append(f"# TSX Module: {module_name}")
46
+ elif is_module:
47
+ lines.append(f"# TypeScript Module: {module_name}")
48
+ else:
49
+ lines.append(f"# TypeScript Script: {module_name}")
50
+ lines.append("")
51
+
52
+ # Imports
53
+ imports = data.get("imports", [])
54
+ if imports:
55
+ lines.append("## Imports")
56
+ lines.append("```typescript")
57
+ for imp in imports:
58
+ import_statement = imp.get("statement", "")
59
+ if not import_statement:
60
+ # Construct import statement from parts
61
+ source = imp.get("source", "")
62
+ name = imp.get("name", "")
63
+ is_type_import = imp.get("is_type_import", False)
64
+ if name and source:
65
+ type_prefix = "type " if is_type_import else ""
66
+ import_statement = f"import {type_prefix}{name} from {source};"
67
+ lines.append(import_statement)
68
+ lines.append("```")
69
+ lines.append("")
70
+
71
+ # Module Info
72
+ stats = data.get("statistics", {})
73
+ classes = data.get("classes", [])
74
+ interfaces = [c for c in classes if c.get("class_type") == "interface"]
75
+ type_aliases = [c for c in classes if c.get("class_type") == "type"]
76
+ enums = [c for c in classes if c.get("class_type") == "enum"]
77
+ actual_classes = [c for c in classes if c.get("class_type") in ["class", "abstract_class"]]
78
+
79
+ lines.append("## Module Info")
80
+ lines.append("| Property | Value |")
81
+ lines.append("|----------|-------|")
82
+ lines.append(f"| File | {file_name} |")
83
+ lines.append(f"| Type | {'Declaration File' if is_declaration_file else 'TSX Module' if is_tsx else 'TypeScript Module' if is_module else 'TypeScript Script'} |")
84
+ lines.append(f"| Functions | {stats.get('function_count', 0)} |")
85
+ lines.append(f"| Classes | {len(actual_classes)} |")
86
+ lines.append(f"| Interfaces | {len(interfaces)} |")
87
+ lines.append(f"| Type Aliases | {len(type_aliases)} |")
88
+ lines.append(f"| Enums | {len(enums)} |")
89
+ lines.append(f"| Variables | {stats.get('variable_count', 0)} |")
90
+ lines.append(f"| Exports | {len(exports)} |")
91
+ lines.append("")
92
+
93
+ # Interfaces (TypeScript specific)
94
+ if interfaces:
95
+ lines.append("## Interfaces")
96
+ lines.append("| Interface | Extends | Lines | Properties | Methods | Generics |")
97
+ lines.append("|-----------|---------|-------|------------|---------|----------|")
98
+
99
+ for interface in interfaces:
100
+ name = str(interface.get("name", "Unknown"))
101
+ extends = ", ".join(interface.get("interfaces", [])) or "-"
102
+ line_range = interface.get("line_range", {})
103
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
104
+
105
+ # Count properties and methods within the interface
106
+ interface_properties = [
107
+ v for v in data.get("variables", [])
108
+ if line_range.get("start", 0) <= v.get("line_range", {}).get("start", 0) <= line_range.get("end", 0)
109
+ and v.get("declaration_kind") == "property_signature"
110
+ ]
111
+
112
+ interface_methods = [
113
+ m for m in data.get("methods", [])
114
+ if line_range.get("start", 0) <= m.get("line_range", {}).get("start", 0) <= line_range.get("end", 0)
115
+ and m.get("is_signature", False)
116
+ ]
117
+
118
+ generics = ", ".join(interface.get("generics", [])) or "-"
119
+
120
+ lines.append(f"| {name} | {extends} | {lines_str} | {len(interface_properties)} | {len(interface_methods)} | {generics} |")
121
+ lines.append("")
122
+
123
+ # Type Aliases (TypeScript specific)
124
+ if type_aliases:
125
+ lines.append("## Type Aliases")
126
+ lines.append("| Type | Lines | Generics | Definition |")
127
+ lines.append("|------|-------|----------|------------|")
128
+
129
+ for type_alias in type_aliases:
130
+ name = str(type_alias.get("name", "Unknown"))
131
+ line_range = type_alias.get("line_range", {})
132
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
133
+ generics = ", ".join(type_alias.get("generics", [])) or "-"
134
+
135
+ # Extract type definition from raw text
136
+ raw_text = type_alias.get("raw_text", "")
137
+ if "=" in raw_text:
138
+ definition = raw_text.split("=", 1)[1].strip().rstrip(";")[:50]
139
+ if len(definition) > 47:
140
+ definition = definition[:47] + "..."
141
+ else:
142
+ definition = "-"
143
+
144
+ lines.append(f"| {name} | {lines_str} | {generics} | {definition} |")
145
+ lines.append("")
146
+
147
+ # Enums (TypeScript specific)
148
+ if enums:
149
+ lines.append("## Enums")
150
+ lines.append("| Enum | Lines | Values |")
151
+ lines.append("|------|-------|--------|")
152
+
153
+ for enum in enums:
154
+ name = str(enum.get("name", "Unknown"))
155
+ line_range = enum.get("line_range", {})
156
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
157
+
158
+ # Count enum values (simplified)
159
+ raw_text = enum.get("raw_text", "")
160
+ value_count = raw_text.count(",") + 1 if raw_text.count("{") > 0 else 0
161
+
162
+ lines.append(f"| {name} | {lines_str} | {value_count} |")
163
+ lines.append("")
164
+
165
+ # Classes
166
+ if actual_classes:
167
+ lines.append("## Classes")
168
+ lines.append("| Class | Type | Extends | Implements | Lines | Methods | Properties | Generics |")
169
+ lines.append("|-------|------|---------|------------|-------|---------|------------|----------|")
170
+
171
+ for class_info in actual_classes:
172
+ name = str(class_info.get("name", "Unknown"))
173
+ class_type = class_info.get("class_type", "class")
174
+ extends = str(class_info.get("superclass", "")) or "-"
175
+ implements = ", ".join(class_info.get("interfaces", [])) or "-"
176
+ line_range = class_info.get("line_range", {})
177
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
178
+ generics = ", ".join(class_info.get("generics", [])) or "-"
179
+
180
+ # Count methods within the class
181
+ class_methods = [
182
+ m for m in data.get("functions", [])
183
+ if (line_range.get("start", 0) <= m.get("line_range", {}).get("start", 0) <= line_range.get("end", 0)
184
+ and m.get("is_method", False)
185
+ and not m.get("is_signature", False))
186
+ ]
187
+
188
+ # Count properties (class fields)
189
+ class_properties = [
190
+ v for v in data.get("variables", [])
191
+ if line_range.get("start", 0) <= v.get("line_range", {}).get("start", 0) <= line_range.get("end", 0)
192
+ and v.get("declaration_kind") == "property"
193
+ ]
194
+
195
+ lines.append(f"| {name} | {class_type} | {extends} | {implements} | {lines_str} | {len(class_methods)} | {len(class_properties)} | {generics} |")
196
+ lines.append("")
197
+
198
+ # Functions
199
+ functions = data.get("functions", [])
200
+ if functions:
201
+ lines.append("## Functions")
202
+ lines.append("| Function | Type | Return Type | Parameters | Async | Generic | Lines | Complexity |")
203
+ lines.append("|----------|------|-------------|------------|-------|---------|-------|------------|")
204
+
205
+ for func in functions:
206
+ name = str(func.get("name", "Unknown"))
207
+ func_type = "arrow" if func.get("is_arrow") else "method" if func.get("is_method") else "function"
208
+ return_type = str(func.get("return_type", "any"))
209
+ params = func.get("parameters", [])
210
+ param_count = len(params)
211
+ is_async = "✓" if func.get("is_async") else ""
212
+ has_generics = "✓" if func.get("generics") else ""
213
+ line_range = func.get("line_range", {})
214
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
215
+ complexity = func.get("complexity_score", 1)
216
+
217
+ lines.append(f"| {name} | {func_type} | {return_type} | {param_count} | {is_async} | {has_generics} | {lines_str} | {complexity} |")
218
+ lines.append("")
219
+
220
+ # Variables/Properties
221
+ variables = data.get("variables", [])
222
+ if variables:
223
+ lines.append("## Variables & Properties")
224
+ lines.append("| Name | Type | Kind | Visibility | Static | Optional | Lines |")
225
+ lines.append("|------|------|------|------------|--------|----------|-------|")
226
+
227
+ for var in variables:
228
+ name = str(var.get("name", "Unknown"))
229
+ var_type = str(var.get("variable_type", "any"))
230
+ kind = var.get("declaration_kind", "variable")
231
+ visibility = var.get("visibility", "public")
232
+ is_static = "✓" if var.get("is_static") else ""
233
+ is_optional = "✓" if var.get("is_optional") else ""
234
+ line_range = var.get("line_range", {})
235
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
236
+
237
+ lines.append(f"| {name} | {var_type} | {kind} | {visibility} | {is_static} | {is_optional} | {lines_str} |")
238
+ lines.append("")
239
+
240
+ # Exports
241
+ if exports:
242
+ lines.append("## Exports")
243
+ lines.append("| Export | Type | Default |")
244
+ lines.append("|--------|------|---------|")
245
+
246
+ for export in exports:
247
+ names = export.get("names", [])
248
+ export_type = export.get("type", "unknown")
249
+ is_default = "✓" if export.get("is_default") else ""
250
+
251
+ for name in names:
252
+ lines.append(f"| {name} | {export_type} | {is_default} |")
253
+ lines.append("")
254
+
255
+ return "\n".join(lines)
256
+
257
+ def _format_compact_table(self, data: dict[str, Any]) -> str:
258
+ """Compact table format for TypeScript"""
259
+ lines = []
260
+
261
+ # Header
262
+ file_path = data.get("file_path", "Unknown")
263
+ file_name = file_path.split("/")[-1].split("\\")[-1]
264
+ lines.append(f"# {file_name}")
265
+ lines.append("")
266
+
267
+ # Summary
268
+ stats = data.get("statistics", {})
269
+ classes = data.get("classes", [])
270
+ functions = data.get("functions", [])
271
+ variables = data.get("variables", [])
272
+
273
+ interfaces = len([c for c in classes if c.get("class_type") == "interface"])
274
+ type_aliases = len([c for c in classes if c.get("class_type") == "type"])
275
+ enums = len([c for c in classes if c.get("class_type") == "enum"])
276
+ actual_classes = len([c for c in classes if c.get("class_type") in ["class", "abstract_class"]])
277
+
278
+ lines.append("## Summary")
279
+ lines.append(f"- **Classes**: {actual_classes}")
280
+ lines.append(f"- **Interfaces**: {interfaces}")
281
+ lines.append(f"- **Type Aliases**: {type_aliases}")
282
+ lines.append(f"- **Enums**: {enums}")
283
+ lines.append(f"- **Functions**: {len(functions)}")
284
+ lines.append(f"- **Variables**: {len(variables)}")
285
+ lines.append("")
286
+
287
+ # Main elements
288
+ if classes:
289
+ lines.append("## Types")
290
+ for class_info in classes:
291
+ name = class_info.get("name", "Unknown")
292
+ class_type = class_info.get("class_type", "class")
293
+ line_range = class_info.get("line_range", {})
294
+ lines_str = f"L{line_range.get('start', 0)}-{line_range.get('end', 0)}"
295
+ lines.append(f"- **{name}** ({class_type}) - {lines_str}")
296
+ lines.append("")
297
+
298
+ if functions:
299
+ lines.append("## Functions")
300
+ for func in functions:
301
+ name = func.get("name", "Unknown")
302
+ return_type = func.get("return_type", "any")
303
+ line_range = func.get("line_range", {})
304
+ lines_str = f"L{line_range.get('start', 0)}-{line_range.get('end', 0)}"
305
+ async_marker = " (async)" if func.get("is_async") else ""
306
+ lines.append(f"- **{name}**(): {return_type}{async_marker} - {lines_str}")
307
+ lines.append("")
308
+
309
+ return "\n".join(lines)
310
+
311
+ def _format_csv(self, data: dict[str, Any]) -> str:
312
+ """CSV format for TypeScript"""
313
+ lines = []
314
+
315
+ # Header
316
+ lines.append("Type,Name,Kind,Return/Type,Lines,Visibility,Static,Async,Generic")
317
+
318
+ # Classes, interfaces, types, enums
319
+ classes = data.get("classes", [])
320
+ for class_info in classes:
321
+ name = class_info.get("name", "")
322
+ class_type = class_info.get("class_type", "class")
323
+ line_range = class_info.get("line_range", {})
324
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
325
+ visibility = class_info.get("visibility", "public")
326
+ is_static = "true" if class_info.get("is_static") else "false"
327
+ has_generics = "true" if class_info.get("generics") else "false"
328
+
329
+ lines.append(f"Class,{name},{class_type},,{lines_str},{visibility},{is_static},,{has_generics}")
330
+
331
+ # Functions
332
+ functions = data.get("functions", [])
333
+ for func in functions:
334
+ name = func.get("name", "")
335
+ func_type = "arrow" if func.get("is_arrow") else "method" if func.get("is_method") else "function"
336
+ return_type = func.get("return_type", "any")
337
+ line_range = func.get("line_range", {})
338
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
339
+ visibility = func.get("visibility", "public")
340
+ is_static = "true" if func.get("is_static") else "false"
341
+ is_async = "true" if func.get("is_async") else "false"
342
+ has_generics = "true" if func.get("generics") else "false"
343
+
344
+ lines.append(f"Function,{name},{func_type},{return_type},{lines_str},{visibility},{is_static},{is_async},{has_generics}")
345
+
346
+ # Variables
347
+ variables = data.get("variables", [])
348
+ for var in variables:
349
+ name = var.get("name", "")
350
+ kind = var.get("declaration_kind", "variable")
351
+ var_type = var.get("variable_type", "any")
352
+ line_range = var.get("line_range", {})
353
+ lines_str = f"{line_range.get('start', 0)}-{line_range.get('end', 0)}"
354
+ visibility = var.get("visibility", "public")
355
+ is_static = "true" if var.get("is_static") else "false"
356
+
357
+ lines.append(f"Variable,{name},{kind},{var_type},{lines_str},{visibility},{is_static},,")
358
+
359
+ return "\n".join(lines)
360
+
361
+ def _get_element_type_name(self, element: dict[str, Any]) -> str:
362
+ """Get human-readable type name for TypeScript elements"""
363
+ element_type = element.get("element_type", "unknown")
364
+
365
+ if element_type == "class":
366
+ class_type = element.get("class_type", "class")
367
+ if class_type == "interface":
368
+ return "Interface"
369
+ elif class_type == "type":
370
+ return "Type Alias"
371
+ elif class_type == "enum":
372
+ return "Enum"
373
+ elif class_type == "abstract_class":
374
+ return "Abstract Class"
375
+ else:
376
+ return "Class"
377
+ elif element_type == "function":
378
+ if element.get("is_arrow"):
379
+ return "Arrow Function"
380
+ elif element.get("is_method"):
381
+ return "Method"
382
+ elif element.get("is_constructor"):
383
+ return "Constructor"
384
+ else:
385
+ return "Function"
386
+ elif element_type == "variable":
387
+ kind = element.get("declaration_kind", "variable")
388
+ if kind == "property":
389
+ return "Property"
390
+ elif kind == "property_signature":
391
+ return "Property Signature"
392
+ else:
393
+ return "Variable"
394
+ elif element_type == "import":
395
+ return "Import"
396
+ else:
397
+ return element_type.title()
398
+
399
+ def _format_element_details(self, element: dict[str, Any]) -> str:
400
+ """Format TypeScript-specific element details"""
401
+ details = []
402
+
403
+ # Type annotations
404
+ if element.get("has_type_annotations"):
405
+ details.append("typed")
406
+
407
+ # Generics
408
+ if element.get("generics"):
409
+ generics = ", ".join(element.get("generics", []))
410
+ details.append(f"<{generics}>")
411
+
412
+ # Visibility
413
+ visibility = element.get("visibility")
414
+ if visibility and visibility != "public":
415
+ details.append(visibility)
416
+
417
+ # Modifiers
418
+ if element.get("is_static"):
419
+ details.append("static")
420
+ if element.get("is_async"):
421
+ details.append("async")
422
+ if element.get("is_abstract"):
423
+ details.append("abstract")
424
+ if element.get("is_optional"):
425
+ details.append("optional")
426
+
427
+ # Framework specific
428
+ framework = element.get("framework_type")
429
+ if framework:
430
+ details.append(f"{framework}")
431
+
432
+ return " ".join(details) if details else ""
@@ -23,7 +23,7 @@ class LanguageDetector:
23
23
  ".js": "javascript",
24
24
  ".jsx": "jsx",
25
25
  ".ts": "typescript",
26
- ".tsx": "tsx",
26
+ ".tsx": "typescript", # TSX files are TypeScript with JSX
27
27
  ".mjs": "javascript",
28
28
  ".cjs": "javascript",
29
29
  # Python系