-
Notifications
You must be signed in to change notification settings - Fork 0
The Graph Model
Everything PolyGraph shows is a projection of one data structure: the GraphModel (lib/graph/types.ts) — nodes, edges, and the evidence behind each edge. This page is the reference for what those are.
A node is a file or a symbol within it. Every node has a kind drawn from a universal, language-neutral taxonomy, so a Rust struct and a TypeScript interface sit in the same vocabulary:
file, class, interface, struct, trait, protocol, enum, union, record, object, type, namespace, module, function, method, constructor, accessor, component, macro, variable, constant, field, property, annotation — plus external (an imported third-party dependency).
Each kind has a color, glyph, and icon (lib/graph/visual.ts) and belongs to a filter layer shown in the sidebar:
| Layer | Kinds |
|---|---|
| Types | class, interface, struct, trait, protocol, enum, union, record, object, type |
| Callables | function, method, constructor, accessor, component, macro |
| Members | field, property, variable, constant, annotation |
| Modules | module, namespace |
Collapse-to-file by default. Files start collapsed; expand a file to see its member-level nodes. This keeps even large graphs legible. The expand/collapse projection lives in lib/aggregate.ts.
PolyGraph draws these relationship types automatically — no configuration:
| Edge | Meaning |
|---|---|
import |
Module dependency between files |
call |
Type-resolved function/method call (resolved via the TypeScript compiler for TS/JS, so two functions named handle link to the correct definition) |
instantiates |
new X() construction |
extends / implements
|
Class & interface inheritance |
has |
Composition — a typed field/property referencing another class or interface (resolved through arrays and generics) |
injects |
Dependency injection — constructor parameter types |
renders |
Which component renders which (JSX usage) |
Repeated relationships read as a thicker edge with a ×N count rather than N separate lines.
This is what separates PolyGraph from a guess. Every edge carries its evidence:
-
occurrences— a list of{ filePath, line, column?, provider }. Occurrences are capped per edge (the cap is 25) but thecountis the true total. -
confidence— one of:-
exact— resolved precisely (e.g. via the TypeScript type checker). -
inferred— resolved by name against the project's symbol index (how the tree-sitter languages resolve). -
ambiguous— more than one plausible target; surfaced in the Problems panel.
-
Click an edge to see exactly where the relationship was observed and how many times. When symbol→symbol edges collapse onto an aggregated file→file edge, the evidence is merged and the underlying edge ids are kept — so the UI can show "what's behind this edge". References PolyGraph couldn't resolve (broken relative imports, ambiguous resolutions) become findings in the Problems panel.
Nodes are tagged with a role (colored + badged), disambiguated by file extension and imports:
-
React (JSX), Vue (
.vueSFCs +defineComponent), Svelte, Angular (@Component/@Injectable/@Directive/@Pipe/@NgModule), and ECS (*Component/*System/*Entity,defineSystem/defineQuery).
These power queries like role:react-component (see Query Language).
Toggle external dependencies in the toolbar (off by default) to bring in imported npm packages, Node builtins, and Bun / Deno / process API usage as dashed external nodes, color-coded by source family. They're enriched from package.json with a version and dependency type: dependency / devDependency / peer / undeclared (imported but not in any manifest — a finding in its own right).
| Provider | Languages |
|---|---|
| Precise (ts-morph) | TypeScript, JavaScript (incl. .mts/.cts/.mjs/.cjs), and JSX/TSX |
| Tree-sitter packs | Python, Java, Kotlin, Rust, Go, Scala, C#, F#, C, C++, Objective-C, Swift, Zig, Haskell, Ruby, PHP, Bash, Lua, Dart, Julia, R, Nix, OCaml, SQL, WebAssembly text |
How each is analyzed — and how to add a new one — is in Language Analysis.
PolyGraph reads project manifests (package.json, Cargo.toml, pyproject.toml/poetry, go.mod, Maven pom.xml, Gradle) and projects the file graph up to package and workspace levels (lib/graph/levels/). A monorepo's module boundaries and cross-package dependencies become a single readable graph. The discovered manifests ride along with the scan response, so switching levels is instant — no re-scan.
PolyGraph — explore, audit, enforce, and compare software architecture across 26 languages, 100% locally. Repository · Releases · Issues · Licensed Apache-2.0 OR MIT
📖 Using PolyGraph
- Installation
- Getting Started
- The Graph Model
- Layouts & Navigation
- Impact Analysis & Insights
- Query Language
- CLI: Rules & Diff
- Exports, Workspaces & Editor
- Troubleshooting & FAQ
🔧 Internals & Contributing