Skip to content

Latest commit

 

History

62 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

outline

Reduce a source tree to a structural skeleton suitable for feeding to an LLM. Function and method bodies are dropped; signatures, types, comments and imports are kept. Unsupported file types pass through unchanged.

Pure Go, no CGo. Parsing is done by gotreesitter, file selection respects .gitignore via git-pkgs/gitignore. Full API docs are on pkg.go.dev.

Installation

Add the library to your Go module:

go get github.com/git-pkgs/outline

For the CLI, see outline binary.

Usage

import "github.com/git-pkgs/outline"

r, err := outline.Pack(".", outline.Options{Compress: true})
if err != nil {
    return err
}
r.Markdown(os.Stdout)

Or per file:

src, _ := os.ReadFile("main.go")
out, ok := outline.Outline(src, "main.go")

A Go file like

func SayHello(name string) {
    fmt.Printf("Hello, %s!\n", name)
}

becomes

func SayHello(name string) {
⋮----

with the body elided and gaps marked by ⋮----.

API

Outline(src []byte, filename string) (string, bool) compresses one file. The second return is false if the language is not supported.

Imports(src []byte, filename string) ([]Import, bool) extracts module imports, their source-language form, named imports, local aliases, and one-based source lines. A statement containing both default and named imports returns one value for each form.

Refs(src []byte, filename string, receivers []string) ([]Ref, bool) extracts direct member accesses on the supplied receiver identifiers. This lets callers pass the local aliases returned by Imports without collecting unrelated member expressions from the file.

imports, ok := outline.Imports(src, "app.py")
if !ok {
    return
}

refs, _ := outline.Refs(src, "app.py", []string{"flask", "f"})

For both functions, false means the language is unsupported or parsing did not complete, including a parse timeout. A true result with an empty slice means the language is supported but the file contains no matches. Import and reference extraction currently cover Go, Ruby, Python, JavaScript, TypeScript/TSX, Rust, PHP, Elixir, Dart, Swift, Haskell, Perl, Lua, R, Julia, OCaml, Crystal, Nim, Zig, D, Java, Kotlin, and C#.

Pack(root string, opts Options) (*Result, error) walks root, applies .gitignore plus a built-in ignore list (vendored deps, build output, lockfiles), skips binaries and oversized files, and outlines what it can. Options lets you set size and file-count limits, extra ignore patterns, concurrency, and whether to compress.

Result carries []File and a rendered Tree string. Result.Markdown(w) and Result.XML(w) write the packed document.

Build(root string, opts Options) (*Graph, error) shares the Pack walker but keeps bin/ entrypoints and returns a directed code graph. Ruby files include .rb, .gemspec, and extensionless files with a Ruby shebang. Nodes are files, modules, declarations, and unresolved external call targets; each edge has a relation (contains, imports, loads, calls) and a confidence (extracted for facts read directly from one AST, inferred for name resolution). Call edges retain the receiver form, dispatch form, arguments, and byte span. Graph methods query the result: Def(name) looks up by node ID, bare name, or qualified name; Callers/Callees return one-hop call edges; Affected(seeds, opts) returns reverse-reachable evidence paths from a set of sinks; Path(from, to, opts) returns the shortest forward call chain; JSON(w) writes sorted output so repeated builds of unchanged input are byte-identical. Go and Python include cross-file call resolution. Ruby includes direct calls, same-file calls within the same class or module, distinct instance and singleton method names, unresolved dynamic receivers, subshells, and local require_relative load edges. Other supported languages contain file, symbol, module, and import structure with call edges omitted.

Tree(paths []string) string renders a box-drawing directory tree from a flat path list.

Supported(filename string) bool reports whether a file's extension maps to a language with an outlining query. SupportedSource(src, filename) also checks source-based detection such as Ruby shebangs.

SetParseTimeout(d time.Duration) overrides the per-file parse timeout (default 1s). Must be called before the first Outline or Pack call.

outline binary

go install github.com/git-pkgs/outline/cmd/outline@latest

outline graph [dir] builds the graph and prints a summary; -json writes it to stdout and -o file to disk. outline def <name>, outline callers <name>, outline callees <name>, outline affected <name>..., and outline path <from> <to> query it. -g file reads a saved graph instead of rebuilding; -inferred includes cross-file name-matched edges alongside extracted ones; -depth N caps traversal hops; -relations r,... selects which edge kinds to follow (default calls); -budget N caps output size in tokens. Flags precede positional arguments.

Seeds take the same forms as Def: Handler, Handler.process, or a full node ID. External targets use ext:<lang>:<module>:<name>, so tracing every declaration that reaches exec.Command from the testdata/cli-go fixture produces:

$ outline affected -inferred -dir testdata/cli-go ext:go:os/exec:Command
2 paths, 3 nodes
NODE Handler func main.go:9 exported=true sig=func Handler(name string) error
NODE os/exec.Command external exported=false sig=
NODE main func main.go:17 exported=false sig=func main()
EDGE Handler --calls[inferred]--> Run at main.go:14
NODE Run external exported=false sig=
EDGE Handler --calls[inferred]--> os/exec.Command at main.go:14
EDGE Handler --calls[inferred]--> Load at main.go:10
NODE Load func store/store.go:7 exported=true sig=func Load(name string) (Record, error)
EDGE main --calls[extracted]--> Handler at main.go:18

Languages

35 languages have body-stripping queries: Go, Ruby, Python, JavaScript, TypeScript/TSX, Rust, Java, C, C++, C#, PHP, Kotlin, Swift, Scala, Dart, Elixir, Erlang, Haskell, Clojure, Perl, Lua, R, Julia, OCaml, F#, Crystal, Nim, Zig, D, Groovy, HCL/Terraform, Starlark/Bazel, CMake, Bash and Make. gotreesitter ships ~200 grammars so adding a language means writing one .scm query file. cmd/outline-compare -dump <lang> prints the S-expression tree for stdin and is the easiest way to work out what to capture.

Performance

On an M1 Pro, outlining runs at ~6 MB/s per core and reaches ~36 MB/s across all eight via the parser pool. Packing a 600-file repo takes about 34ms; the Markdown render of that result is ~140µs. Almost all the time is in gotreesitter's full-parse path; chunk extraction and rendering barely register.

License

MIT.

About

Reduce a source tree to a structural skeleton suitable for feeding to an LLM.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

11 stars

Watchers

2 watching

Forks

Releases

Used by

Contributors

Languages