ast-outline 0.4.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.
- ast_outline-0.4.3/.gitignore +32 -0
- ast_outline-0.4.3/LICENSE +21 -0
- ast_outline-0.4.3/PKG-INFO +611 -0
- ast_outline-0.4.3/README.md +574 -0
- ast_outline-0.4.3/pyproject.toml +96 -0
- ast_outline-0.4.3/src/ast_outline/__init__.py +7 -0
- ast_outline-0.4.3/src/ast_outline/_prompt.py +58 -0
- ast_outline-0.4.3/src/ast_outline/adapters/__init__.py +71 -0
- ast_outline-0.4.3/src/ast_outline/adapters/base.py +40 -0
- ast_outline-0.4.3/src/ast_outline/adapters/csharp.py +411 -0
- ast_outline-0.4.3/src/ast_outline/adapters/go.py +763 -0
- ast_outline-0.4.3/src/ast_outline/adapters/java.py +573 -0
- ast_outline-0.4.3/src/ast_outline/adapters/kotlin.py +858 -0
- ast_outline-0.4.3/src/ast_outline/adapters/markdown.py +257 -0
- ast_outline-0.4.3/src/ast_outline/adapters/python.py +276 -0
- ast_outline-0.4.3/src/ast_outline/adapters/rust.py +1109 -0
- ast_outline-0.4.3/src/ast_outline/adapters/scala.py +975 -0
- ast_outline-0.4.3/src/ast_outline/adapters/typescript.py +672 -0
- ast_outline-0.4.3/src/ast_outline/adapters/yaml.py +740 -0
- ast_outline-0.4.3/src/ast_outline/cli.py +611 -0
- ast_outline-0.4.3/src/ast_outline/core.py +1223 -0
- ast_outline-0.4.3/tests/conftest.py +59 -0
- ast_outline-0.4.3/tests/fixtures/csharp/broken_syntax.cs +18 -0
- ast_outline-0.4.3/tests/fixtures/csharp/file_scoped_ns.cs +41 -0
- ast_outline-0.4.3/tests/fixtures/csharp/hierarchy.cs +52 -0
- ast_outline-0.4.3/tests/fixtures/csharp/nested_and_overloads.cs +50 -0
- ast_outline-0.4.3/tests/fixtures/csharp/unity_behaviour.cs +53 -0
- ast_outline-0.4.3/tests/fixtures/csharp/visibility_defaults.cs +23 -0
- ast_outline-0.4.3/tests/fixtures/go/broken_syntax.go +12 -0
- ast_outline-0.4.3/tests/fixtures/go/comments_edge.go +19 -0
- ast_outline-0.4.3/tests/fixtures/go/edge_cases.go +106 -0
- ast_outline-0.4.3/tests/fixtures/go/enum_iota.go +37 -0
- ast_outline-0.4.3/tests/fixtures/go/generics.go +45 -0
- ast_outline-0.4.3/tests/fixtures/go/hierarchy.go +49 -0
- ast_outline-0.4.3/tests/fixtures/go/multidir/base/animal.go +12 -0
- ast_outline-0.4.3/tests/fixtures/go/multidir/felines/cat.go +11 -0
- ast_outline-0.4.3/tests/fixtures/go/multidir/mammals/dog.go +17 -0
- ast_outline-0.4.3/tests/fixtures/go/multidir/mammals/puppy.go +6 -0
- ast_outline-0.4.3/tests/fixtures/go/no_package_methods.go +22 -0
- ast_outline-0.4.3/tests/fixtures/go/user_service.go +104 -0
- ast_outline-0.4.3/tests/fixtures/java/annotation_type.java +33 -0
- ast_outline-0.4.3/tests/fixtures/java/broken_syntax.java +15 -0
- ast_outline-0.4.3/tests/fixtures/java/generics_throws.java +35 -0
- ast_outline-0.4.3/tests/fixtures/java/hierarchy.java +42 -0
- ast_outline-0.4.3/tests/fixtures/java/line_comment.java +4 -0
- ast_outline-0.4.3/tests/fixtures/java/multi_var_fields.java +21 -0
- ast_outline-0.4.3/tests/fixtures/java/multidir/base/Animal.java +6 -0
- ast_outline-0.4.3/tests/fixtures/java/multidir/felines/Cat.java +9 -0
- ast_outline-0.4.3/tests/fixtures/java/multidir/mammals/Dog.java +9 -0
- ast_outline-0.4.3/tests/fixtures/java/multidir/mammals/Puppy.java +7 -0
- ast_outline-0.4.3/tests/fixtures/java/no_package.java +15 -0
- ast_outline-0.4.3/tests/fixtures/java/plain_block_comment.java +4 -0
- ast_outline-0.4.3/tests/fixtures/java/records_and_sealed.java +70 -0
- ast_outline-0.4.3/tests/fixtures/java/repository.java +39 -0
- ast_outline-0.4.3/tests/fixtures/java/status_enum.java +38 -0
- ast_outline-0.4.3/tests/fixtures/java/user_service.java +63 -0
- ast_outline-0.4.3/tests/fixtures/kotlin/annotations_generics.kt +35 -0
- ast_outline-0.4.3/tests/fixtures/kotlin/broken_syntax.kt +7 -0
- ast_outline-0.4.3/tests/fixtures/kotlin/companion_and_objects.kt +46 -0
- ast_outline-0.4.3/tests/fixtures/kotlin/data_and_sealed.kt +40 -0
- ast_outline-0.4.3/tests/fixtures/kotlin/extensions_and_toplevel.kt +30 -0
- ast_outline-0.4.3/tests/fixtures/kotlin/hierarchy.kt +26 -0
- ast_outline-0.4.3/tests/fixtures/kotlin/line_comment.kt +5 -0
- ast_outline-0.4.3/tests/fixtures/kotlin/multidir/base/Animal.kt +5 -0
- ast_outline-0.4.3/tests/fixtures/kotlin/multidir/felines/Cat.kt +7 -0
- ast_outline-0.4.3/tests/fixtures/kotlin/multidir/mammals/Dog.kt +7 -0
- ast_outline-0.4.3/tests/fixtures/kotlin/multidir/mammals/Puppy.kt +3 -0
- ast_outline-0.4.3/tests/fixtures/kotlin/no_package.kt +11 -0
- ast_outline-0.4.3/tests/fixtures/kotlin/plain_block_comment.kt +4 -0
- ast_outline-0.4.3/tests/fixtures/kotlin/properties.kt +31 -0
- ast_outline-0.4.3/tests/fixtures/kotlin/secondary_ctor.kt +17 -0
- ast_outline-0.4.3/tests/fixtures/kotlin/user_service.kt +58 -0
- ast_outline-0.4.3/tests/fixtures/markdown/article.md +33 -0
- ast_outline-0.4.3/tests/fixtures/markdown/decorated_headings.md +20 -0
- ast_outline-0.4.3/tests/fixtures/markdown/empty.md +3 -0
- ast_outline-0.4.3/tests/fixtures/markdown/readme_style.md +51 -0
- ast_outline-0.4.3/tests/fixtures/markdown/setext_and_codes.md +26 -0
- ast_outline-0.4.3/tests/fixtures/python/async_service.py +53 -0
- ast_outline-0.4.3/tests/fixtures/python/broken_syntax.py +16 -0
- ast_outline-0.4.3/tests/fixtures/python/decorators_edge.py +44 -0
- ast_outline-0.4.3/tests/fixtures/python/domain_model.py +83 -0
- ast_outline-0.4.3/tests/fixtures/python/hierarchy.py +55 -0
- ast_outline-0.4.3/tests/fixtures/rust/broken_syntax.rs +17 -0
- ast_outline-0.4.3/tests/fixtures/rust/comments_edge.rs +40 -0
- ast_outline-0.4.3/tests/fixtures/rust/cross_file_impl.rs +32 -0
- ast_outline-0.4.3/tests/fixtures/rust/edge_cases.rs +28 -0
- ast_outline-0.4.3/tests/fixtures/rust/enum_advanced.rs +32 -0
- ast_outline-0.4.3/tests/fixtures/rust/extern_block.rs +22 -0
- ast_outline-0.4.3/tests/fixtures/rust/generics.rs +58 -0
- ast_outline-0.4.3/tests/fixtures/rust/hierarchy.rs +58 -0
- ast_outline-0.4.3/tests/fixtures/rust/modules.rs +29 -0
- ast_outline-0.4.3/tests/fixtures/rust/unions_and_macros.rs +32 -0
- ast_outline-0.4.3/tests/fixtures/rust/user_service.rs +71 -0
- ast_outline-0.4.3/tests/fixtures/rust/visibility_matrix.rs +19 -0
- ast_outline-0.4.3/tests/fixtures/scala/braced_package.scala +11 -0
- ast_outline-0.4.3/tests/fixtures/scala/broken_syntax.scala +8 -0
- ast_outline-0.4.3/tests/fixtures/scala/companion_and_objects.scala +39 -0
- ast_outline-0.4.3/tests/fixtures/scala/data_and_sealed.scala +32 -0
- ast_outline-0.4.3/tests/fixtures/scala/extensions_and_toplevel.scala +21 -0
- ast_outline-0.4.3/tests/fixtures/scala/hierarchy.scala +27 -0
- ast_outline-0.4.3/tests/fixtures/scala/line_comment.scala +5 -0
- ast_outline-0.4.3/tests/fixtures/scala/multidir/base/Animal.scala +5 -0
- ast_outline-0.4.3/tests/fixtures/scala/multidir/felines/Cat.scala +7 -0
- ast_outline-0.4.3/tests/fixtures/scala/multidir/mammals/Dog.scala +7 -0
- ast_outline-0.4.3/tests/fixtures/scala/multidir/mammals/Puppy.scala +3 -0
- ast_outline-0.4.3/tests/fixtures/scala/no_package.scala +11 -0
- ast_outline-0.4.3/tests/fixtures/scala/package_object.scala +11 -0
- ast_outline-0.4.3/tests/fixtures/scala/plain_block_comment.scala +4 -0
- ast_outline-0.4.3/tests/fixtures/scala/scala3_features.scala +29 -0
- ast_outline-0.4.3/tests/fixtures/scala/user_service.scala +56 -0
- ast_outline-0.4.3/tests/fixtures/typescript/broken_syntax.ts +16 -0
- ast_outline-0.4.3/tests/fixtures/typescript/decorators.ts +29 -0
- ast_outline-0.4.3/tests/fixtures/typescript/hierarchy.ts +40 -0
- ast_outline-0.4.3/tests/fixtures/typescript/plain_module.js +25 -0
- ast_outline-0.4.3/tests/fixtures/typescript/react_page.tsx +40 -0
- ast_outline-0.4.3/tests/fixtures/typescript/storage_service.ts +59 -0
- ast_outline-0.4.3/tests/fixtures/typescript/types.ts +34 -0
- ast_outline-0.4.3/tests/fixtures/typescript/visibility.ts +18 -0
- ast_outline-0.4.3/tests/fixtures/yaml/anchors_aliases.yaml +12 -0
- ast_outline-0.4.3/tests/fixtures/yaml/app_config.yaml +26 -0
- ast_outline-0.4.3/tests/fixtures/yaml/block_scalars.yaml +15 -0
- ast_outline-0.4.3/tests/fixtures/yaml/broken_syntax.yaml +11 -0
- ast_outline-0.4.3/tests/fixtures/yaml/dotted_keys.yaml +21 -0
- ast_outline-0.4.3/tests/fixtures/yaml/github_workflow.yaml +20 -0
- ast_outline-0.4.3/tests/fixtures/yaml/helm_templated.yaml +22 -0
- ast_outline-0.4.3/tests/fixtures/yaml/k8s_deployment.yaml +36 -0
- ast_outline-0.4.3/tests/fixtures/yaml/k8s_multi_resources.yaml +38 -0
- ast_outline-0.4.3/tests/fixtures/yaml/openapi_mini.yaml +57 -0
- ast_outline-0.4.3/tests/fixtures/yaml/seq_id_fallback.yaml +30 -0
- ast_outline-0.4.3/tests/sample.cs +50 -0
- ast_outline-0.4.3/tests/sample.py +59 -0
- ast_outline-0.4.3/tests/unit/__init__.py +0 -0
- ast_outline-0.4.3/tests/unit/test_cli.py +348 -0
- ast_outline-0.4.3/tests/unit/test_core_renderers.py +185 -0
- ast_outline-0.4.3/tests/unit/test_core_search.py +716 -0
- ast_outline-0.4.3/tests/unit/test_csharp_adapter.py +289 -0
- ast_outline-0.4.3/tests/unit/test_digest_format.py +1208 -0
- ast_outline-0.4.3/tests/unit/test_go_adapter.py +709 -0
- ast_outline-0.4.3/tests/unit/test_header_enrichment.py +644 -0
- ast_outline-0.4.3/tests/unit/test_java_adapter.py +658 -0
- ast_outline-0.4.3/tests/unit/test_kotlin_adapter.py +677 -0
- ast_outline-0.4.3/tests/unit/test_markdown_adapter.py +214 -0
- ast_outline-0.4.3/tests/unit/test_prompt_command.py +205 -0
- ast_outline-0.4.3/tests/unit/test_python_adapter.py +256 -0
- ast_outline-0.4.3/tests/unit/test_rust_adapter.py +1118 -0
- ast_outline-0.4.3/tests/unit/test_scala_adapter.py +587 -0
- ast_outline-0.4.3/tests/unit/test_typescript_adapter.py +347 -0
- ast_outline-0.4.3/tests/unit/test_yaml_adapter.py +519 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Virtual environments
|
|
2
|
+
.venv/
|
|
3
|
+
venv/
|
|
4
|
+
env/
|
|
5
|
+
|
|
6
|
+
# Python build / bytecode
|
|
7
|
+
__pycache__/
|
|
8
|
+
*.py[cod]
|
|
9
|
+
*$py.class
|
|
10
|
+
*.egg-info/
|
|
11
|
+
dist/
|
|
12
|
+
build/
|
|
13
|
+
.eggs/
|
|
14
|
+
|
|
15
|
+
# Tooling caches
|
|
16
|
+
.pytest_cache/
|
|
17
|
+
.mypy_cache/
|
|
18
|
+
.ruff_cache/
|
|
19
|
+
.tox/
|
|
20
|
+
.coverage
|
|
21
|
+
htmlcov/
|
|
22
|
+
|
|
23
|
+
# IDE / OS
|
|
24
|
+
.DS_Store
|
|
25
|
+
.idea/
|
|
26
|
+
.vscode/
|
|
27
|
+
*.swp
|
|
28
|
+
*.swo
|
|
29
|
+
|
|
30
|
+
# Distribution
|
|
31
|
+
*.whl
|
|
32
|
+
*.tar.gz
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ast-outline contributors (formerly code-outline)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: ast-outline
|
|
3
|
+
Version: 0.4.3
|
|
4
|
+
Summary: AST-based structural outline for source files (C#, Python, TypeScript/JavaScript, Java, Kotlin, Scala, Go, Rust, Markdown, YAML) — tree-sitter-powered, LLM-agent-first. Complement to ast-grep: ast-grep searches, ast-outline overviews.
|
|
5
|
+
Project-URL: Homepage, https://github.com/dim-s/ast-outline
|
|
6
|
+
Project-URL: Issues, https://github.com/dim-s/ast-outline/issues
|
|
7
|
+
Project-URL: Repository, https://github.com/dim-s/ast-outline
|
|
8
|
+
Author: ast-outline contributors
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: ast,ast-grep,code-navigation,coding-agent,csharp,go,golang,java,javascript,kotlin,kubernetes,llm,markdown,openapi,outline,python,rust,scala,tree-sitter,typescript,yaml
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
21
|
+
Classifier: Topic :: Utilities
|
|
22
|
+
Requires-Python: >=3.10
|
|
23
|
+
Requires-Dist: tree-sitter-c-sharp>=0.23
|
|
24
|
+
Requires-Dist: tree-sitter-go>=0.23
|
|
25
|
+
Requires-Dist: tree-sitter-java>=0.23
|
|
26
|
+
Requires-Dist: tree-sitter-kotlin>=1.1
|
|
27
|
+
Requires-Dist: tree-sitter-markdown>=0.3
|
|
28
|
+
Requires-Dist: tree-sitter-python>=0.23
|
|
29
|
+
Requires-Dist: tree-sitter-rust>=0.23
|
|
30
|
+
Requires-Dist: tree-sitter-scala>=0.24
|
|
31
|
+
Requires-Dist: tree-sitter-typescript>=0.23
|
|
32
|
+
Requires-Dist: tree-sitter-yaml>=0.6
|
|
33
|
+
Requires-Dist: tree-sitter>=0.23
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
# ast-outline
|
|
39
|
+
|
|
40
|
+
**English** · [Русский](./README.ru.md) · [简体中文](./README.zh-CN.md)
|
|
41
|
+
|
|
42
|
+
> **Renamed from `code-outline` in v0.3.0** to join the `ast-*` family convention popularised by [ast-grep](https://github.com/ast-grep/ast-grep). The legacy `code-outline` CLI command still works as a backward-compat alias through 0.4.x.
|
|
43
|
+
|
|
44
|
+
> Fast, AST-based **structural outline** for source files — classes, methods,
|
|
45
|
+
> signatures with line numbers, but **no method bodies**. Built for LLM coding
|
|
46
|
+
> agents that should read the *shape* of a file before reading the whole thing.
|
|
47
|
+
|
|
48
|
+
[](./LICENSE)
|
|
49
|
+

|
|
50
|
+

|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Purpose
|
|
55
|
+
|
|
56
|
+
**`ast-outline` exists to make LLM coding agents faster, cheaper, and smarter
|
|
57
|
+
when navigating unfamiliar code.**
|
|
58
|
+
|
|
59
|
+
Modern agentic coding tools (Claude Code, Cursor's agent mode, Aider,
|
|
60
|
+
Copilot Chat, custom CLI agents) explore codebases by reading files directly
|
|
61
|
+
— not via embeddings or vector search. That approach is reliable but has a
|
|
62
|
+
cost: on a 1000-line file, the agent pays for 1000 lines of tokens just to
|
|
63
|
+
answer *"what methods exist here?"*.
|
|
64
|
+
|
|
65
|
+
`ast-outline` closes that gap. It's a **pre-reading layer** for agents:
|
|
66
|
+
|
|
67
|
+
1. **Token savings — typically 5–10×.** An outline replaces a full file
|
|
68
|
+
read when the agent only needs structural understanding.
|
|
69
|
+
2. **Faster exploration.** A whole module's public API fits on one screen.
|
|
70
|
+
3. **Precise navigation.** Every declaration has a line range (`L42-58`).
|
|
71
|
+
The agent goes straight to the method body it needs.
|
|
72
|
+
4. **AST accuracy, not fuzzy match.** `implements` and `show` understand
|
|
73
|
+
real syntax — no false positives from comments or strings.
|
|
74
|
+
5. **Zero infrastructure.** No index, no cache, no embeddings, no network.
|
|
75
|
+
Live, always fresh, invisible to your repo.
|
|
76
|
+
|
|
77
|
+
### The typical agent workflow
|
|
78
|
+
|
|
79
|
+
**Before `ast-outline`:**
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
Agent: Read Player.cs # 1200 lines of tokens
|
|
83
|
+
Agent: Read Enemy.cs # 800 lines of tokens
|
|
84
|
+
Agent: Read DamageSystem.cs # 400 lines of tokens
|
|
85
|
+
Agent: grep "IDamageable" src/ # noisy, lots of false matches
|
|
86
|
+
...
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**With `ast-outline`:**
|
|
90
|
+
|
|
91
|
+
```
|
|
92
|
+
Agent: ast-outline digest src/Combat # ~100 lines, whole module
|
|
93
|
+
Agent: ast-outline implements IDamageable # precise list, no grep noise
|
|
94
|
+
Agent: ast-outline show Player.cs TakeDamage # just the method body
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Result: **same understanding, a fraction of the tokens, a fraction of
|
|
98
|
+
the round-trips.**
|
|
99
|
+
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Supported languages
|
|
103
|
+
|
|
104
|
+
| Language | Extensions |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| C# | `.cs` |
|
|
107
|
+
| Python | `.py`, `.pyi` |
|
|
108
|
+
| TypeScript | `.ts`, `.tsx` |
|
|
109
|
+
| JavaScript | `.js`, `.jsx`, `.mjs`, `.cjs` (parsed by the TypeScript grammar) |
|
|
110
|
+
| Java | `.java` — classes, interfaces, `@interface`, enums, records, sealed hierarchies, generics, throws, Javadoc |
|
|
111
|
+
| Kotlin | `.kt`, `.kts` — classes, interfaces, `fun interface`, `object` / `companion object`, `data` / `sealed` / `enum` / `annotation` classes, extension functions, `suspend` / `inline` / `const` / `lateinit`, generics with `where` constraints, `typealias`, KDoc |
|
|
112
|
+
| Scala | `.scala`, `.sc` — Scala 2 + Scala 3: classes, traits, `object` / `case object`, `case class`, `sealed` hierarchies, Scala 3 `enum` / `given` / `using` / `extension`, indentation-based bodies, higher-kinded types, context bounds, `opaque type`, `type` aliases, Scaladoc |
|
|
113
|
+
| Go | `.go` — packages, structs (with method-grouping under receiver), interfaces, struct/interface embedding as inheritance, generics (Go 1.18+), `type` aliases + defined types, `iota` enum-blocks, doc-comment chains |
|
|
114
|
+
| Rust | `.rs` — modules (recursive), structs (regular / tuple / unit), unions, enums with all variant shapes, traits with supertraits as bases, **`impl` block regrouping under the target type** (inherent + `impl Trait for Foo` adds Trait to bases), `extern "C"` blocks, `macro_rules!`, type aliases, generics + lifetimes + `where` clauses, `pub` / `pub(crate)` visibility, outer doc comments (`///`, `/** */`) and `#[...]` attributes |
|
|
115
|
+
| Markdown | `.md`, `.markdown`, `.mdx`, `.mdown` — heading TOC + fenced code blocks |
|
|
116
|
+
| YAML | `.yaml`, `.yml` — key hierarchy with line ranges, `[i]` sequence paths, multi-document separators, format-detect for Kubernetes / OpenAPI / GitHub Actions in the header |
|
|
117
|
+
|
|
118
|
+
Adding another language is a single new adapter file. See
|
|
119
|
+
[`src/ast_outline/adapters/`](src/ast_outline/adapters/).
|
|
120
|
+
|
|
121
|
+
#### YAML caveats
|
|
122
|
+
|
|
123
|
+
Real-world YAML files routinely surface a `# WARNING: N parse errors`
|
|
124
|
+
header — `tree-sitter-yaml`'s strict parser flags fairly innocuous
|
|
125
|
+
inconsistencies (like a sequence item nested inside an unexpected
|
|
126
|
+
mapping context) and the error region can spread well beyond the
|
|
127
|
+
actual broken line. The adapter's recovery walk salvages most useful
|
|
128
|
+
structure around such regions; treat the outline as best-effort and
|
|
129
|
+
fall back to `Read` for the affected region when the answer is
|
|
130
|
+
load-bearing.
|
|
131
|
+
|
|
132
|
+
`show` for YAML matches **keys**, not value text. `show file.yaml
|
|
133
|
+
"some phrase"` will not find a phrase that lives inside a string
|
|
134
|
+
value — for free-text searches inside values, use `grep`/`rg`.
|
|
135
|
+
`ast-outline` is structural; it complements text search rather than
|
|
136
|
+
replacing it.
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Install
|
|
141
|
+
|
|
142
|
+
### One-liner (recommended — macOS / Linux / Windows)
|
|
143
|
+
|
|
144
|
+
Requires [`uv`](https://docs.astral.sh/uv/) (a fast Python package manager):
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
uv tool install git+https://github.com/dim-s/ast-outline.git
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
This installs the `ast-outline` CLI globally into `~/.local/bin` (Mac / Linux)
|
|
151
|
+
or `%USERPROFILE%\.local\bin` (Windows) — make sure that's on your `PATH`.
|
|
152
|
+
|
|
153
|
+
Don't have `uv` yet?
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# macOS / Linux
|
|
157
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh
|
|
158
|
+
|
|
159
|
+
# Windows (PowerShell)
|
|
160
|
+
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
### Using the install scripts in this repo
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
# macOS / Linux
|
|
167
|
+
curl -LsSf https://raw.githubusercontent.com/dim-s/ast-outline/main/scripts/install.sh | bash
|
|
168
|
+
|
|
169
|
+
# Windows (PowerShell)
|
|
170
|
+
iwr -useb https://raw.githubusercontent.com/dim-s/ast-outline/main/scripts/install.ps1 | iex
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Alternative: `pipx`
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
pipx install git+https://github.com/dim-s/ast-outline.git
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Alternative: `pip` (into an active venv)
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
pip install git+https://github.com/dim-s/ast-outline.git
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Update / uninstall
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
uv tool upgrade ast-outline
|
|
189
|
+
uv tool uninstall ast-outline
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Quick start
|
|
195
|
+
|
|
196
|
+
```bash
|
|
197
|
+
# Structural outline of one file
|
|
198
|
+
ast-outline path/to/Player.cs
|
|
199
|
+
ast-outline path/to/user_service.py
|
|
200
|
+
|
|
201
|
+
# Outline a whole directory (recurses supported extensions)
|
|
202
|
+
ast-outline src/
|
|
203
|
+
|
|
204
|
+
# Print the source of one specific method
|
|
205
|
+
ast-outline show Player.cs TakeDamage
|
|
206
|
+
|
|
207
|
+
# Several methods at once
|
|
208
|
+
ast-outline show Player.cs TakeDamage Heal Die
|
|
209
|
+
|
|
210
|
+
# Compact public-API map of a whole module
|
|
211
|
+
ast-outline digest src/Services
|
|
212
|
+
|
|
213
|
+
# Every class that inherits/implements a given type
|
|
214
|
+
ast-outline implements IDamageable src/
|
|
215
|
+
|
|
216
|
+
# Built-in guide
|
|
217
|
+
ast-outline help
|
|
218
|
+
ast-outline help show
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Using with LLM coding agents
|
|
224
|
+
|
|
225
|
+
This is the main use case. Add the snippet below to your `CLAUDE.md`,
|
|
226
|
+
`AGENTS.md`, subagent file, or any system prompt that steers a coding
|
|
227
|
+
agent. It will then prefer `ast-outline` over reading full files.
|
|
228
|
+
|
|
229
|
+
The same snippet ships with the tool — `ast-outline prompt` prints it
|
|
230
|
+
verbatim, so you can append it to a project's agent config without
|
|
231
|
+
copy-pasting:
|
|
232
|
+
|
|
233
|
+
```bash
|
|
234
|
+
ast-outline prompt >> AGENTS.md
|
|
235
|
+
ast-outline prompt >> .claude/CLAUDE.md
|
|
236
|
+
ast-outline prompt | pbcopy # macOS clipboard
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Prompt snippet (copy-paste)
|
|
240
|
+
|
|
241
|
+
```markdown
|
|
242
|
+
## Code exploration — prefer `ast-outline` over full reads
|
|
243
|
+
|
|
244
|
+
For `.cs`, `.py`, `.pyi`, `.ts`, `.tsx`, `.js`, `.jsx`, `.java`, `.kt`, `.kts`,
|
|
245
|
+
`.scala`, `.sc`, `.go`, `.rs`, `.md`, and `.yaml`/`.yml` files, read structure
|
|
246
|
+
with `ast-outline` before opening full contents.
|
|
247
|
+
|
|
248
|
+
Stop at the step that answers the question:
|
|
249
|
+
|
|
250
|
+
1. **Unfamiliar directory** — `ast-outline digest <paths…>`: one-page map
|
|
251
|
+
of every file's types and public methods. Each file is tagged with a
|
|
252
|
+
size label — `[tiny]` / `[medium]` / `[large]` — plus `[broken]`
|
|
253
|
+
when parse errors may have left the outline partial.
|
|
254
|
+
|
|
255
|
+
2. **File-level shape** — `ast-outline <paths…>`: signatures with line
|
|
256
|
+
ranges, no bodies (5–10× smaller than a full read on non-trivial
|
|
257
|
+
files). A `# WARNING: N parse errors` line in the header means the
|
|
258
|
+
outline is partial — read the source for the affected region.
|
|
259
|
+
|
|
260
|
+
3. **One method, type, markdown heading, or yaml key** —
|
|
261
|
+
`ast-outline show <file> <Symbol>`. Suffix matching: `TakeDamage`
|
|
262
|
+
for one method; `User` for an entire type — class, struct, interface,
|
|
263
|
+
trait, enum (whole body, useful when a file holds several types);
|
|
264
|
+
`Player.TakeDamage` when ambiguous. Multiple at once:
|
|
265
|
+
`ast-outline show Player.cs TakeDamage Heal Die`.
|
|
266
|
+
For markdown, the symbol is heading text and matching is
|
|
267
|
+
case-insensitive substring — `"installation"` finds
|
|
268
|
+
`"2.1 Installation (macOS / Linux)"`. For yaml, the symbol is a
|
|
269
|
+
dotted key path (`spec.containers[0].image`) — `show` matches keys,
|
|
270
|
+
not values, so for free-text search inside values use `grep`.
|
|
271
|
+
|
|
272
|
+
4. **Who implements/extends a type** — `ast-outline implements <Type>
|
|
273
|
+
<paths…>`: AST-accurate (skip `grep`), transitive by default with
|
|
274
|
+
`[via Parent]` tags on indirect matches. Add `--direct` for level-1 only.
|
|
275
|
+
|
|
276
|
+
`outline`, `digest`, `implements` accept multiple paths in one call
|
|
277
|
+
(files and directories, mixed languages OK) — batch instead of looping.
|
|
278
|
+
|
|
279
|
+
Fall back to a full read only when you need context beyond the body
|
|
280
|
+
`show` returned. `ast-outline help` for flags.
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Why this helps
|
|
284
|
+
|
|
285
|
+
- **Fresh subagents with shallow context** (like Claude Code's `Explore`
|
|
286
|
+
agent) can scan a whole module in one call instead of 10–20 `Read`/`grep`
|
|
287
|
+
rounds.
|
|
288
|
+
- **"Where is X defined?"** becomes one `implements` or `show` call.
|
|
289
|
+
- **Line ranges** (`L42-58`) turn the outline into a precise navigator —
|
|
290
|
+
the agent reads only the lines it needs.
|
|
291
|
+
- **AST-based** `implements` has no false positives from string literals,
|
|
292
|
+
comments, or unrelated name mentions — unlike `grep`.
|
|
293
|
+
|
|
294
|
+
### Works with
|
|
295
|
+
|
|
296
|
+
- Claude Code (+ custom subagents like `Explore`, `codebase-scout`)
|
|
297
|
+
- Cursor agent mode
|
|
298
|
+
- Aider
|
|
299
|
+
- Copilot Chat / Workspace
|
|
300
|
+
- Any custom agent on the Claude / OpenAI / Gemini APIs
|
|
301
|
+
- Humans (the format is readable; `show` is a nice alternative to `grep -A 20`)
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
305
|
+
## Commands
|
|
306
|
+
|
|
307
|
+
### `outline` — default
|
|
308
|
+
|
|
309
|
+
Print the file's classes, methods, properties, fields with line ranges.
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
ast-outline path/to/File.cs
|
|
313
|
+
ast-outline path/to/module.py --no-private --no-fields
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
Flags:
|
|
317
|
+
|
|
318
|
+
- `--no-private` — hide private members (Python: names starting with `_`)
|
|
319
|
+
- `--no-fields` — hide field declarations
|
|
320
|
+
- `--no-docs` — hide `///` XML-doc / docstrings
|
|
321
|
+
- `--no-attrs` — hide `[Attributes]` / `@decorators`
|
|
322
|
+
- `--no-lines` — hide line-number suffixes
|
|
323
|
+
- `--glob PATTERN` — restrict directory mode to a pattern
|
|
324
|
+
|
|
325
|
+
### `show` — extract source of a symbol
|
|
326
|
+
|
|
327
|
+
```bash
|
|
328
|
+
ast-outline show File.cs TakeDamage
|
|
329
|
+
ast-outline show File.cs PlayerController.TakeDamage # disambiguate overloads
|
|
330
|
+
ast-outline show service.py UserService.get
|
|
331
|
+
ast-outline show File.cs TakeDamage Heal Die # several at once
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
For code, matching is **suffix-based**: `Foo.Bar` matches any `*.Foo.Bar`. If
|
|
335
|
+
multiple declarations match, all are printed with a summary.
|
|
336
|
+
|
|
337
|
+
For markdown, matching is **case-insensitive substring** per dotted part.
|
|
338
|
+
LLM agents rarely remember the exact decoration of a heading (number prefixes
|
|
339
|
+
like `1.`, trailing `(Feb 2026)`, `(Confidence: 70%)`), so a fuzzy core works:
|
|
340
|
+
|
|
341
|
+
```bash
|
|
342
|
+
ast-outline show forecast.md "current analysis"
|
|
343
|
+
# → matches `## 1. CURRENT ANALYSIS (Feb 2026)`
|
|
344
|
+
|
|
345
|
+
ast-outline show forecast.md "scenario.transit"
|
|
346
|
+
# → matches `### SCENARIO A: "MANAGED TRANSIT"` under any parent
|
|
347
|
+
# heading containing "scenario"
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
If the substring matches several headings, all are printed and the
|
|
351
|
+
disambiguation summary lands on stderr — tighten the query to narrow.
|
|
352
|
+
|
|
353
|
+
### `digest` — one-page module map
|
|
354
|
+
|
|
355
|
+
```bash
|
|
356
|
+
ast-outline digest src/
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
Sample output:
|
|
360
|
+
|
|
361
|
+
```
|
|
362
|
+
# legend: name()=callable, name [kind]=non-callable, marker name()=method modifier (async/static/override/…), [N overloads]=N callables share name, [deprecated]=obsolete, L<a>-<b>=line range, : Base, …=inheritance
|
|
363
|
+
src/services/
|
|
364
|
+
__init__.py [tiny] (8 lines, ~74 tokens, 1 fields)
|
|
365
|
+
user_service.py [medium] (140 lines, ~1,200 tokens, 1 types, 5 methods)
|
|
366
|
+
@Service abstract class UserService [deprecated] : IUserService L8-138
|
|
367
|
+
async get(), async search(), abstract create(), delete(), update_v1() [deprecated]
|
|
368
|
+
|
|
369
|
+
auth_service.py [medium] (95 lines, ~840 tokens, 1 types, 4 methods)
|
|
370
|
+
[ApiController] sealed class AuthService L10-95
|
|
371
|
+
async login(), logout(), refresh(), override verify_token()
|
|
372
|
+
|
|
373
|
+
legacy_repo.py [large] [broken] (5234 lines, ~52,000 tokens, ...)
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
The first line is a self-describing legend so an LLM can read the
|
|
377
|
+
output cold without `ast-outline prompt` loaded. Tokens follow the
|
|
378
|
+
universal programming-doc convention — `name()` for a callable,
|
|
379
|
+
`name [kind]` for a property/field/event/etc., method markers
|
|
380
|
+
(`async`, `static`, `abstract`, `override`, `virtual`, plus
|
|
381
|
+
language-native forms: Kotlin `open` / `suspend`, Python
|
|
382
|
+
`@staticmethod` / `@classmethod` / `@abstractmethod`, Java
|
|
383
|
+
`@Override`) prefix the name source-true so each language reads in
|
|
384
|
+
its own idiom. `[N overloads]` flags when several callables share a
|
|
385
|
+
name; `[deprecated]` whenever a type or member carries
|
|
386
|
+
`@Deprecated` / `[Obsolete]` / `#[deprecated]`. Type headers also
|
|
387
|
+
carry inline decorators / attributes (`@dataclass`, `[ApiController]`,
|
|
388
|
+
`#[derive(Debug)]`) and semantic modifiers (`abstract`, `sealed`,
|
|
389
|
+
`static`, `final`, `open`, `partial`) so runtime contracts and
|
|
390
|
+
instantiation rules read off at a glance. Members are joined with
|
|
391
|
+
`, `; types that have a body get a trailing blank line as a
|
|
392
|
+
paragraph break, empty types stack tightly so digest stays compact.
|
|
393
|
+
Source-language keywords (Rust `trait`, Scala `object`, Kotlin
|
|
394
|
+
`data class`) are preserved in the type header instead of the
|
|
395
|
+
canonical kind.
|
|
396
|
+
|
|
397
|
+
Each filename gets a descriptive size label — `[tiny]` (under ~500 tokens),
|
|
398
|
+
`[medium]` (500–5000), `[large]` (5000+). A `[broken]` marker appears next
|
|
399
|
+
to the size label when the parse hit syntax errors and the outline may be
|
|
400
|
+
partial. The labels describe the file; they don't prescribe an action.
|
|
401
|
+
An LLM agent reads them, weighs its task (does it need the whole file? a
|
|
402
|
+
single section? just structure?) and picks Read / outline / show accordingly
|
|
403
|
+
— the tool informs, the agent decides.
|
|
404
|
+
|
|
405
|
+
The label conventions live in the canonical agent prompt (`ast-outline prompt`)
|
|
406
|
+
so they're paid for once per session, not on every digest call. Size class is
|
|
407
|
+
calibrated against an approximate token count (`len(chars)/4`, ±15-20% vs
|
|
408
|
+
real BPE tokenizers — fine for the heuristic). The same `~N tokens` count
|
|
409
|
+
appears in every `outline` header too.
|
|
410
|
+
|
|
411
|
+
### `implements` — find subclasses / implementations
|
|
412
|
+
|
|
413
|
+
```bash
|
|
414
|
+
ast-outline implements IDamageable src/
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
AST-based — no false positives from comments or unrelated mentions.
|
|
418
|
+
**Transitive by default**: if `Puppy extends Dog extends Animal`, then
|
|
419
|
+
`implements Animal` returns all three, with an annotation on indirect
|
|
420
|
+
matches:
|
|
421
|
+
|
|
422
|
+
```
|
|
423
|
+
# 3 match(es) for 'Animal' (incl. transitive):
|
|
424
|
+
src/Animals.cs:5 class Dog : Animal
|
|
425
|
+
src/Cats.cs:3 class Cat : Animal
|
|
426
|
+
src/Puppies.cs:12 class Puppy : Dog [via Dog]
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
Add `--direct` / `-d` to restrict to level-1 subclasses only:
|
|
430
|
+
|
|
431
|
+
```bash
|
|
432
|
+
ast-outline implements --direct IDamageable src/
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
The search works across any number of files and nested directories —
|
|
436
|
+
no reliance on filename↔classname convention. Matching is by the last
|
|
437
|
+
segment of the type name (stripping generics and namespace prefixes).
|
|
438
|
+
|
|
439
|
+
### `prompt` — print the agent prompt snippet
|
|
440
|
+
|
|
441
|
+
```bash
|
|
442
|
+
ast-outline prompt
|
|
443
|
+
ast-outline prompt >> AGENTS.md
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
Prints the canonical copy-paste snippet used to steer LLM coding agents
|
|
447
|
+
to prefer `ast-outline` over full reads. English, universal across
|
|
448
|
+
Claude Opus 4.7 / Sonnet 4.6 / Haiku 4.5. Running it ensures you always
|
|
449
|
+
get the current recommended version.
|
|
450
|
+
|
|
451
|
+
---
|
|
452
|
+
|
|
453
|
+
## Output format
|
|
454
|
+
|
|
455
|
+
The format is designed to be **LLM-friendly**: Python-style indentation,
|
|
456
|
+
line-number suffixes in `L<start>-<end>` form, doc-comments preserved.
|
|
457
|
+
The header summarises scale and flags partial parses.
|
|
458
|
+
|
|
459
|
+
### C#
|
|
460
|
+
|
|
461
|
+
```
|
|
462
|
+
# Player.cs (142 lines, 3 types, 12 methods, 5 fields)
|
|
463
|
+
namespace Game.Player
|
|
464
|
+
[RequireComponent(typeof(Rigidbody2D))] public class PlayerController : MonoBehaviour, IDamageable L10-120
|
|
465
|
+
[SerializeField] private float speed = 5f L12
|
|
466
|
+
public int CurrentHealth { get; private set; } L15
|
|
467
|
+
/// <summary>Apply damage.</summary>
|
|
468
|
+
public void TakeDamage(int amount) L30-48
|
|
469
|
+
private void Die() L50-55
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
### Python
|
|
473
|
+
|
|
474
|
+
```
|
|
475
|
+
# user_service.py (70 lines, 2 types, 5 methods, 3 fields)
|
|
476
|
+
@dataclass class User L16-29
|
|
477
|
+
def display_name(self) -> str L26-29
|
|
478
|
+
"""Human-friendly label."""
|
|
479
|
+
|
|
480
|
+
class UserService L31-58
|
|
481
|
+
def __init__(self, storage: Storage) -> None L34-35
|
|
482
|
+
def get(self, user_id: int) -> User | None L37-42
|
|
483
|
+
"""Look up a user by id."""
|
|
484
|
+
def save(self, user: User) -> None L44-46
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
### `show` with ancestor context
|
|
488
|
+
|
|
489
|
+
`ast-outline show <file> <Symbol>` prints a `# in: ...` breadcrumb
|
|
490
|
+
between the header and the body so you know what the extracted code is
|
|
491
|
+
nested inside, without a second `outline` call:
|
|
492
|
+
|
|
493
|
+
```
|
|
494
|
+
# Player.cs:30-48 Game.Player.PlayerController.TakeDamage (method)
|
|
495
|
+
# in: namespace Game.Player → public class PlayerController : MonoBehaviour, IDamageable
|
|
496
|
+
/// <summary>Apply damage.</summary>
|
|
497
|
+
public void TakeDamage(int amount) { ... }
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
Top-level symbols (no enclosing namespace/type) have no breadcrumb.
|
|
501
|
+
|
|
502
|
+
### Partial parses
|
|
503
|
+
|
|
504
|
+
When tree-sitter recovers from syntax errors, the outline is kept but a
|
|
505
|
+
second header line flags the gap:
|
|
506
|
+
|
|
507
|
+
```
|
|
508
|
+
# broken.java (16 lines, 1 types, 3 methods)
|
|
509
|
+
# WARNING: 3 parse errors — output may be incomplete
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
Agents should treat these files as partial and read the source directly
|
|
513
|
+
for the affected region.
|
|
514
|
+
|
|
515
|
+
Differences are language-idiomatic:
|
|
516
|
+
|
|
517
|
+
- C# `///` XML-doc appears **above** the signature.
|
|
518
|
+
- Python `"""docstrings"""` appear **below** the signature with one extra
|
|
519
|
+
indent (matching Python semantics).
|
|
520
|
+
- C# attributes (`[Attr]`) and Python decorators (`@foo`) are inlined with
|
|
521
|
+
the declaration.
|
|
522
|
+
- C# property accessors `{ get; private set; }` are preserved.
|
|
523
|
+
|
|
524
|
+
---
|
|
525
|
+
|
|
526
|
+
## How it works (briefly)
|
|
527
|
+
|
|
528
|
+
- Parses source with [tree-sitter](https://tree-sitter.github.io/) —
|
|
529
|
+
real AST, not regex.
|
|
530
|
+
- Language-specific adapters convert the AST to a uniform
|
|
531
|
+
`Declaration` intermediate representation.
|
|
532
|
+
- Language-agnostic renderers produce outline / digest / search output.
|
|
533
|
+
- Purely local, no network, no indexing, no cache — just reads and parses
|
|
534
|
+
the files you ask about.
|
|
535
|
+
|
|
536
|
+
No vector database, no embedding, no RAG. This is deliberate — the philosophy
|
|
537
|
+
matches how agentic coding tools like Claude Code actually work.
|
|
538
|
+
|
|
539
|
+
---
|
|
540
|
+
|
|
541
|
+
## Development
|
|
542
|
+
|
|
543
|
+
```bash
|
|
544
|
+
git clone https://github.com/dim-s/ast-outline.git
|
|
545
|
+
cd ast-outline
|
|
546
|
+
|
|
547
|
+
# Create a venv and install in editable mode
|
|
548
|
+
uv venv
|
|
549
|
+
uv pip install -e .
|
|
550
|
+
|
|
551
|
+
# Run against the included samples
|
|
552
|
+
.venv/bin/ast-outline tests/sample.cs
|
|
553
|
+
.venv/bin/ast-outline tests/sample.py
|
|
554
|
+
.venv/bin/ast-outline digest tests/
|
|
555
|
+
```
|
|
556
|
+
|
|
557
|
+
### Running the tests
|
|
558
|
+
|
|
559
|
+
Tests are an optional dev dependency — end users don't pull them in. Install
|
|
560
|
+
them once and run via `pytest`:
|
|
561
|
+
|
|
562
|
+
```bash
|
|
563
|
+
# Install pytest into the same venv as the editable install
|
|
564
|
+
uv pip install -e ".[dev]"
|
|
565
|
+
|
|
566
|
+
# Run the full suite (takes ~0.1s)
|
|
567
|
+
.venv/bin/pytest
|
|
568
|
+
|
|
569
|
+
# Just one file, verbose
|
|
570
|
+
.venv/bin/pytest tests/unit/test_csharp_adapter.py -v
|
|
571
|
+
|
|
572
|
+
# Match by test name
|
|
573
|
+
.venv/bin/pytest -k file_scoped_namespace -v
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
The suite (600+ tests) covers every adapter (C#, Python, TypeScript/JS,
|
|
577
|
+
Java, Kotlin, Scala, Go, Rust, Markdown, YAML), the language-agnostic
|
|
578
|
+
renderers, symbol search, and the CLI end-to-end. Fixtures live under `tests/fixtures/`;
|
|
579
|
+
tests never reach outside that directory.
|
|
580
|
+
New behaviour should come with a test; new languages should ship with a
|
|
581
|
+
dedicated fixture directory and a `tests/unit/test_<lang>_adapter.py` file.
|
|
582
|
+
|
|
583
|
+
### Adding a new language
|
|
584
|
+
|
|
585
|
+
Create `src/ast_outline/adapters/<lang>.py` implementing the
|
|
586
|
+
`LanguageAdapter` protocol (see `adapters/base.py`). Then register it in
|
|
587
|
+
`adapters/__init__.py`. The core renderers and CLI pick it up automatically
|
|
588
|
+
— no further wiring needed.
|
|
589
|
+
|
|
590
|
+
---
|
|
591
|
+
|
|
592
|
+
## Roadmap
|
|
593
|
+
|
|
594
|
+
- [x] TypeScript / JavaScript adapter (`.ts`, `.tsx`, `.js`, `.jsx`, `.mjs`, `.cjs`)
|
|
595
|
+
- [x] Java adapter (`.java`) — classes, interfaces, `@interface`, enums, records, sealed hierarchies, generics, throws, Javadoc
|
|
596
|
+
- [x] Kotlin adapter (`.kt`, `.kts`) — classes, interfaces, `fun interface`, `object` / `companion object`, `data` / `sealed` / `enum` / `annotation` classes, extension functions, `suspend` / `inline` / `const` / `lateinit`, generics with `where` constraints, `typealias`, KDoc
|
|
597
|
+
- [x] Scala adapter (`.scala`, `.sc`) — Scala 2 + Scala 3: classes, traits, `object` / `case object`, `case class`, `sealed` hierarchies, Scala 3 `enum` / `given` / `using` / `extension`, indentation-based bodies, higher-kinded types, context bounds, `opaque type`, `type` aliases, Scaladoc
|
|
598
|
+
- [x] Go adapter (`.go`) — packages, structs (with method-grouping under receiver), interfaces, struct/interface embedding as inheritance, generics (Go 1.18+), `type` aliases + defined types, `iota` enum-blocks, doc-comment chains
|
|
599
|
+
- [x] Rust adapter (`.rs`) — modules (recursive), structs (regular / tuple / unit), unions, enums with all variant shapes, traits + supertraits as bases, **`impl` block regrouping under the target type** (inherent + `impl Trait for Foo` adds Trait to bases), `extern "C"` blocks, `macro_rules!`, type aliases, generics + lifetimes + `where` clauses, full visibility classifier (`pub` / `pub(crate)` / `pub(super)` / `pub(in path)`), outer doc comments + `#[...]` attributes
|
|
600
|
+
- [x] Markdown adapter (`.md`, `.markdown`, `.mdx`, `.mdown`) — heading TOC + code blocks
|
|
601
|
+
- [x] YAML adapter (`.yaml`, `.yml`) — key hierarchy, `[i]` sequence paths, multi-document support, format-detect for Kubernetes / OpenAPI / GitHub Actions
|
|
602
|
+
- [ ] `--format json` output mode for programmatic consumers
|
|
603
|
+
- [ ] Optional multiprocessing for very large codebases (>500 files)
|
|
604
|
+
|
|
605
|
+
Contributions welcome.
|
|
606
|
+
|
|
607
|
+
---
|
|
608
|
+
|
|
609
|
+
## License
|
|
610
|
+
|
|
611
|
+
[MIT](./LICENSE)
|