Docs
RepoLens reads a project and gives you a map of how its files connect, plus a short, prioritised list of things worth a look.
Using the app
- Open a project. Choose a folder, pick a ZIP, or drop either anywhere on the page. Dropped folders skip
node_modules,.gitand build output automatically. - Turn the map. Drag to rotate, scroll to zoom, shift-drag to pan, double-click a file to centre it. Files are grouped by folder into labelled constellations; colour them by language, folder, risk or kind.
- Select a file to see its neighbours: what it imports (teal) and what imports it (gold). Use What depends on it to light up its full blast radius, or Trace path to… to show the exact chain of imports between two files.
- Work the list. “Fix first” in the left rail is the shortest useful to-do list. Findings, Hotspots, Architecture and Packages give the full picture.
- Share. Export a JSON report (reopenable here), a Markdown summary, or a PNG of the map. Press Ctrl K for the command palette.
Command line
npx repolens [path] [options]
--json <file> write the full report (open it later in the app)
--md <file> write a Markdown summary
--impact <file> list every file affected by changing <file>
--fail-on <level> exit 1 on: secret | error | warning | cycle
--min-score <n> exit 1 when the health score is below n
--max-files <n> analyse up to n files (default 5000)
--no-gitignore do not apply the project's .gitignoreThe folder’s .gitignore is respected by default, symbolic links are never followed, and the tool makes no network connections.
In CI
# .github/workflows/repolens.yml
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 22 }
- run: npx repolens . --fail-on secret --min-score 70 --md repolens.mdSupported languages
| Language | How imports are found |
|---|---|
| JavaScript, TypeScript, JSX, TSX | Parsed with the TypeScript compiler. import, export … from, require, literal import(), type-only edges, tsconfig/jsconfig paths and baseUrl. |
| Vue, Svelte, Astro | Script blocks (and Astro frontmatter) are parsed as TypeScript. |
| Python | import / from … import, absolute and relative, packages, namespace packages. |
| Java, Kotlin, Scala | Imports matched to each file’s package declaration, including static and wildcard imports. |
| Go | Import blocks resolved through go.mod module paths to package directories. |
| Rust | mod, use (including braced lists), crate::, self::, super::. |
| C, C++ | #include "…" resolved relative to the file, common include directories and unique path suffixes. |
| C# | using matched to namespace declarations. |
| Ruby, PHP, Dart, Swift | require / require_relative, require / include / use, import / export / part, import. |
Other languages’ files are not analysed in depth. Only JavaScript/TypeScript is parsed by a real compiler; the rest use comment-aware pattern matching, which is dependable for imports but not a full parser.
What each finding means
Every finding is labelled confirmed (a fact about the graph) or review (a judgement call that needs a human). Findings are ordered by a priority that multiplies severity and certainty by how much of the project depends on the files involved.
| Finding | Certainty | Meaning |
|---|---|---|
| Credential | confirmed / review | A value shaped like an API key, token, private key or password appears in source. The value is never stored. Rotate it if real. |
| Cycle | confirmed | Files import each other in a loop (type-only imports are excluded). The shortest loop is shown. |
| Directory cycle | confirmed | Directories depend on each other sideways or downward. A child importing from its own parent folder is not counted. |
| Broken import | review | A relative or aliased import that resolves to no included file. |
| Syntax error | confirmed | JavaScript/TypeScript the compiler cannot parse, or an invalid package.json. |
| Risky code | review | eval, raw HTML injection, shell execution, unsafe deserialization, disabled TLS checks, weak hashes and similar. Sometimes legitimate. |
| Complexity | confirmed (JS/TS) / review | A function with cyclomatic complexity of 15 or more (each branch, loop, case and boolean operator counts one). |
| Untested | review | A widely-used file that no test file reaches through imports. Shown only when the project has tests. |
| Undeclared package | review | An imported package that no covering package.json lists. |
| Unused package | review | A production dependency with no traced import. |
| Unused export | review | A named export that nothing in the project imports. Library entry points may use it legitimately. |
| Unreachable | review | No import path connects the file to a recognised entry point. Dynamic loading and framework conventions can cause false positives. |
| Duplicate | confirmed | Source files with identical text. |
| Layering | review | A stable directory depending on a volatile one. |
How scores are calculated
Health score
Start at 100 and subtract capped penalties for: exposed credentials (up to 30), syntax errors (15), circular dependencies (18), broken imports (8), risky constructs (8), complex functions (8), untested or untested-project (8), duplicates (6) and unused code (6). Except for credentials and syntax errors, penalties are divided by a size factor (the square root of the number of code files over 20, between 1 and 4), so a large project is not punished for simply being large. Every deduction is listed in the app under “How it is scored”. Grades: A ≥ 90, B ≥ 80, C ≥ 70, D ≥ 55, otherwise E.
Change risk (per file)
38% blast radius (how many files are affected, on a log scale) + 27% complexity of the most complex function + 15% not reached by any test + 10% size + 10% being part of a cycle. It is a prompt for where to look first, not a prediction.
Blast radius and centrality
Blast radius counts every file that depends on a file directly or through any chain of imports, each counted once. Centrality is PageRank over the import graph: high when important files lean on it.
Report format
Reports are JSON with schemaVersion: 2: nodes (files with metrics and 3D positions), edges, findings, folders, folderEdges, externals, health and fixFirst. They contain paths and findings only, never source text or secret values. When you open one, it is validated against strict bounds before use.
Limits
- Browser: 60,000 files, 100 MB readable text, 1 MB per file, ZIP up to 100 MB. Dependencies, build output and (optionally)
.gitignored files are skipped before reading. Over the limit, you get an error straight away and can open a subfolder or use the command line. - Command line: 60,000 files by default (
--max-files). - Computed imports, reflection, dependency injection, macros, package export maps and build-generated files cannot be traced.
- Java, Kotlin, Scala, Go and C# files in the same package or namespace see each other without imports; those links are not drawn.