codebread 1.0.0__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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Danial Irsyad
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,254 @@
1
+ Metadata-Version: 2.4
2
+ Name: codebread
3
+ Version: 1.0.0
4
+ Summary: Interactive codebase analyzer & visualizer — slice open a project and see how it's wired together.
5
+ Author: Danial Irsyad
6
+ License: MIT
7
+ Keywords: codebase,analyzer,visualizer,call-graph,architecture
8
+ Requires-Python: >=3.9
9
+ Description-Content-Type: text/markdown
10
+ License-File: LICENSE
11
+ Provides-Extra: full
12
+ Requires-Dist: pathspec>=0.11; extra == "full"
13
+ Dynamic: license-file
14
+
15
+ <p align="center">
16
+ <img src="assets/logo-wordmark.png" alt="CodeBread" width="360">
17
+ </p>
18
+
19
+ <p align="center">
20
+ <b>Slice open any codebase and see how it's actually wired together.</b><br>
21
+ An interactive, zero-dependency map of files → functions → API routes → database tables.
22
+ </p>
23
+
24
+ <p align="center">
25
+ <img alt="version" src="https://img.shields.io/badge/version-1.0.0-2dd4bf">
26
+ <img alt="python" src="https://img.shields.io/badge/python-3.9%2B-0284c7">
27
+ <img alt="deps" src="https://img.shields.io/badge/required%20dependencies-none-2dd4bf">
28
+ <img alt="license" src="https://img.shields.io/badge/license-MIT-8b5cf6">
29
+ </p>
30
+
31
+ ---
32
+
33
+ ## What is this
34
+
35
+ CodeBread scans a project, extracts every function and class, maps how
36
+ everything connects — **frontend → API → backend → database** — and renders
37
+ it as an interactive node-graph in your browser. Click a file to slice it
38
+ open into its functions; click a function to see everything it calls and
39
+ everything that calls it, with the full chain lit up end to end.
40
+
41
+ **The problem it solves:** dropping into a codebase you didn't write — or one
42
+ an AI generated for you — and not knowing where anything is. Reading files
43
+ one at a time doesn't build a mental model fast. CodeBread builds the model
44
+ for you: it finds the routes, follows the `fetch()` calls to the handlers
45
+ that answer them, follows the handlers to the tables they touch, and draws
46
+ the whole path.
47
+
48
+ ## Why I built this
49
+
50
+ This started as a personal tool. I kept generating projects with AI and then
51
+ staring at the result with no idea how the pieces fit together — which file
52
+ called which, where the API boundary actually was, what touched the
53
+ database. I wanted something that would just *show* me, instead of me
54
+ grepping through the tree file by file. CodeBread is that tool.
55
+
56
+ It's a v1.0 — actively used by me on my own projects, and I'll keep adding
57
+ to it. If it's useful to you too, that's a bonus. Issues and PRs are welcome.
58
+
59
+ ## What it's built with
60
+
61
+ - **Backend/analysis engine:** pure Python **standard library** — no
62
+ required third-party packages, nothing to `pip install` beyond Python
63
+ itself. Parsing is stdlib `ast` for Python and structural regex for
64
+ everything else (see language table below).
65
+ - **Frontend:** vanilla **JavaScript + SVG**, no framework, no build step,
66
+ no `npm install`. The entire UI is three files (`app.js`, `index.html`,
67
+ `style.css`).
68
+ - **Serving:** a tiny local server built on `http.server` from the stdlib.
69
+
70
+ That's it. Clone it, run it, nothing to compile.
71
+
72
+ ---
73
+
74
+ ## Install
75
+
76
+ ```bash
77
+ # option A: install the CLI
78
+ pip install .
79
+
80
+ # option B: don't install anything, just run it
81
+ python codebread.py --path /path/to/project
82
+ ```
83
+
84
+ Optional extra (better `.gitignore` matching while scanning):
85
+
86
+ ```bash
87
+ pip install .[full] # adds pathspec
88
+ ```
89
+
90
+ Requires **Python 3.9+**. Nothing else.
91
+
92
+ ## Use
93
+
94
+ ```bash
95
+ codebread --path /path/to/project # scan + open the UI in your browser
96
+ codebread # prompts for the path
97
+ python codebread.py --path . # uninstalled, same thing
98
+ ```
99
+
100
+ That's the whole quick start: point it at a folder, a browser tab opens with
101
+ the map already scanned.
102
+
103
+ ### CLI reference
104
+
105
+ | Flag | What it does |
106
+ |---|---|
107
+ | `--path, -p PATH` | root folder to scan (prompted if omitted) |
108
+ | `--port 8137` | local server port (auto-picks a free one nearby if taken) |
109
+ | `--json out.json` | export the full graph as JSON |
110
+ | `--load out.json` | re-open a saved scan without re-scanning |
111
+ | `--html out.html` | export a **self-contained static HTML** file you can share |
112
+ | `--diff old.json new.json` | compare two saved scans and print what changed (files/functions/tables added, removed, changed) |
113
+ | `--no-open` | don't auto-open the browser |
114
+ | `--no-serve` | scan + export only, don't start the server |
115
+ | `--version` | print the installed version |
116
+
117
+ ---
118
+
119
+ ## What you get
120
+
121
+ - **Explorer sidebar** — the full folder tree, expandable like a file
122
+ explorer; every file tagged with its layer color.
123
+ - **Orbit layout (default)** — files float freely in space, spread apart so
124
+ connections stay untangled. Expand a file and its functions arrange in a
125
+ clean ring around it, spoked by straight lines back to the center. A
126
+ **Free** force-directed layout is also available (toggle bottom-right).
127
+ - **Focus mode** — clears the canvas so you inspect one file at a time:
128
+ pick a file in the Explorer and only it, its functions, and its direct
129
+ connections show up. Toggle it off to go back to the full overview.
130
+ - **Progressive reveal (OSINT-style)** — click a file to slice it open into
131
+ its numbered functions; click a function to draw in what it calls and
132
+ what calls it. Dense codebases stay readable.
133
+ - **Full-chain highlight** — select any node and its complete end-to-end
134
+ chain lights up (frontend `fetch()` → `GET /api/users` route → handler →
135
+ `users` table), everything unrelated dims.
136
+ - **Right-click for actions** — a context menu on every node, edge, and
137
+ the empty canvas: reveal connections, focus a file, open it in the IDE
138
+ view, jump to a route's source/target, copy a name or path, and more.
139
+ - **Insights panel** — flags orphaned functions (no detected callers) and
140
+ circular call chains, both clickable to jump straight to them.
141
+ - **Diff mode** — compare two saved scans (`--diff old.json new.json`) to
142
+ see exactly what changed between them.
143
+ - **Minimap + breadcrumb** — a live minimap of the whole graph with a
144
+ draggable viewport, and a breadcrumb showing the real folder path of
145
+ whatever's currently selected.
146
+ - **Keyboard navigation** — `←`/`→` step through a selected node's
147
+ neighbors, `↑`/`↓` walk back/forward through your selection history,
148
+ `/` to search.
149
+ - **Detail panel** — params, return type, auto-generated description
150
+ ("Function 3 · handles GET /api/users · queries users"), every caller and
151
+ callee, clickable.
152
+ - **View the actual code** — every function has an expandable
153
+ **▸ View code** section: syntax-highlighted source with real line
154
+ numbers. A full **IDE view** (⌗) opens any file whole, with an outline
155
+ sidebar.
156
+ - **Search** (`/`) and **layer filter** (Frontend / Backend / Database /
157
+ Config) in the header.
158
+ - **Warnings, never silence** — unreadable files, unsupported languages and
159
+ permission problems show up as ⚠ badges and in the warnings list, never
160
+ hidden. Secrets found in config files are always masked.
161
+
162
+ ## Language support
163
+
164
+ | Language | Parser | Extracted |
165
+ |---|---|---|
166
+ | Python | stdlib `ast` (precise) | functions, classes, params/annotations, docstrings, Flask/FastAPI/Django routes, SQLAlchemy/Django models, raw SQL, `requests`/`httpx` calls |
167
+ | JavaScript / TypeScript / JSX / TSX / Vue / Svelte | structural regex + brace matching | functions, arrow fns, classes, Express/Nest/Fastify routes, `fetch`/`axios` calls, Mongoose/Prisma/Sequelize/Knex/TypeORM, raw SQL |
168
+ | Java, C#, Go, PHP, Ruby | structural regex | functions/methods, classes, Spring/ASP.NET/Laravel/Rails/Gin routes, raw SQL |
169
+ | SQL | regex | `CREATE TABLE` schemas with columns |
170
+ | Config (`.env`, json/yaml/toml/ini, settings.py…) | key scan | DB connection settings — **credentials always masked** |
171
+ | Anything else (Rust, Kotlin, Swift, C/C++…) | — | shown in the UI as "⚠ Unsupported — parsing skipped", never silently dropped |
172
+
173
+ ## How it classifies layers
174
+
175
+ Score-based heuristics combining framework import signatures
176
+ (React/Vue → frontend, Flask/Express → backend, SQLAlchemy/Prisma →
177
+ database), folder conventions (`/client`, `/server`, `/models`…), file
178
+ extensions, and extracted facts (defines routes → backend, defines models →
179
+ database). Ambiguous files are marked **Unclassified** instead of guessed.
180
+
181
+ ## How orphan + cycle detection works
182
+
183
+ - **Orphaned functions**: any function/method with zero detected incoming
184
+ calls, that isn't a route handler and isn't a common framework entry
185
+ point (`__init__`, `main`, `setUp`, test functions, …). Flagged with a
186
+ badge on the node and listed in the Insights panel — a good starting
187
+ point for finding dead code (heuristic, not exhaustive: it can miss calls
188
+ the static parser doesn't recognize).
189
+ - **Circular call chains**: an iterative cycle-detection pass over the
190
+ call graph (no recursion, so it's safe on large codebases) flags
191
+ functions that call each other in a loop, both on the node (↻ badge) and
192
+ as a listed chain in the Insights panel.
193
+
194
+ ## Project layout
195
+
196
+ ```
197
+ codebread.py ← runnable entry point (no install needed)
198
+ codebread/
199
+ cli.py ← argparse CLI
200
+ scanner.py ← .gitignore-aware recursive walker
201
+ languages.py ← language detection / binary sniffing
202
+ parsers/
203
+ python_parser.py ← ast-based Python extractor
204
+ javascript_parser.py ← JS/TS/Vue/Svelte extractor
205
+ generic_parser.py ← Java/C#/Go/PHP/Ruby + SQL + config
206
+ classifier.py ← frontend/backend/database/config scoring
207
+ connections.py ← call graph + API↔route + fn↔table matching +
208
+ orphan/cycle detection
209
+ analyzer.py ← pipeline orchestration
210
+ diff.py ← compares two saved scans
211
+ server.py ← stdlib local web server
212
+ export.py ← JSON + single-file HTML export
213
+ web/ ← the UI (vanilla JS + SVG, zero dependencies)
214
+ assets/ ← logo (.svg source + .png for the README —
215
+ GitHub blocks same-repo SVG <img> embeds)
216
+ ```
217
+
218
+ ---
219
+
220
+ ## Roadmap
221
+
222
+ Already done as of v1.0:
223
+
224
+ - [x] Orphaned-function and circular-dependency detection
225
+ - [x] Diff mode between two scans
226
+ - [x] Focus mode, orbit layout, right-click actions, minimap, breadcrumb
227
+
228
+ Not yet, but planned:
229
+
230
+ - [ ] "Explain this function" — a plain-language AI summary button
231
+ - [ ] More precise multi-language parsing (currently structural regex for
232
+ everything but Python)
233
+ - [ ] An automated test suite
234
+
235
+ Have an idea? Open an issue.
236
+
237
+ ## Contributing
238
+
239
+ This is a young, actively-changing personal project, so keep that in mind —
240
+ but contributions are genuinely welcome:
241
+
242
+ - **Bugs / ideas** → open an issue with a repro or a description.
243
+ - **Pull requests** → welcome, especially for language parser improvements
244
+ or UI polish. Keep the zero-dependency philosophy: the core tool should
245
+ keep running on nothing but the Python standard library, and the UI
246
+ should keep running on vanilla JS with no build step.
247
+ - No formal test suite yet, so please describe how you manually verified a
248
+ change in your PR.
249
+
250
+ ## License
251
+
252
+ [MIT](LICENSE) — use it, modify it, ship it, sell it. No attribution
253
+ required beyond keeping the license file. See [LICENSE](LICENSE) for the
254
+ full text.
@@ -0,0 +1,240 @@
1
+ <p align="center">
2
+ <img src="assets/logo-wordmark.png" alt="CodeBread" width="360">
3
+ </p>
4
+
5
+ <p align="center">
6
+ <b>Slice open any codebase and see how it's actually wired together.</b><br>
7
+ An interactive, zero-dependency map of files → functions → API routes → database tables.
8
+ </p>
9
+
10
+ <p align="center">
11
+ <img alt="version" src="https://img.shields.io/badge/version-1.0.0-2dd4bf">
12
+ <img alt="python" src="https://img.shields.io/badge/python-3.9%2B-0284c7">
13
+ <img alt="deps" src="https://img.shields.io/badge/required%20dependencies-none-2dd4bf">
14
+ <img alt="license" src="https://img.shields.io/badge/license-MIT-8b5cf6">
15
+ </p>
16
+
17
+ ---
18
+
19
+ ## What is this
20
+
21
+ CodeBread scans a project, extracts every function and class, maps how
22
+ everything connects — **frontend → API → backend → database** — and renders
23
+ it as an interactive node-graph in your browser. Click a file to slice it
24
+ open into its functions; click a function to see everything it calls and
25
+ everything that calls it, with the full chain lit up end to end.
26
+
27
+ **The problem it solves:** dropping into a codebase you didn't write — or one
28
+ an AI generated for you — and not knowing where anything is. Reading files
29
+ one at a time doesn't build a mental model fast. CodeBread builds the model
30
+ for you: it finds the routes, follows the `fetch()` calls to the handlers
31
+ that answer them, follows the handlers to the tables they touch, and draws
32
+ the whole path.
33
+
34
+ ## Why I built this
35
+
36
+ This started as a personal tool. I kept generating projects with AI and then
37
+ staring at the result with no idea how the pieces fit together — which file
38
+ called which, where the API boundary actually was, what touched the
39
+ database. I wanted something that would just *show* me, instead of me
40
+ grepping through the tree file by file. CodeBread is that tool.
41
+
42
+ It's a v1.0 — actively used by me on my own projects, and I'll keep adding
43
+ to it. If it's useful to you too, that's a bonus. Issues and PRs are welcome.
44
+
45
+ ## What it's built with
46
+
47
+ - **Backend/analysis engine:** pure Python **standard library** — no
48
+ required third-party packages, nothing to `pip install` beyond Python
49
+ itself. Parsing is stdlib `ast` for Python and structural regex for
50
+ everything else (see language table below).
51
+ - **Frontend:** vanilla **JavaScript + SVG**, no framework, no build step,
52
+ no `npm install`. The entire UI is three files (`app.js`, `index.html`,
53
+ `style.css`).
54
+ - **Serving:** a tiny local server built on `http.server` from the stdlib.
55
+
56
+ That's it. Clone it, run it, nothing to compile.
57
+
58
+ ---
59
+
60
+ ## Install
61
+
62
+ ```bash
63
+ # option A: install the CLI
64
+ pip install .
65
+
66
+ # option B: don't install anything, just run it
67
+ python codebread.py --path /path/to/project
68
+ ```
69
+
70
+ Optional extra (better `.gitignore` matching while scanning):
71
+
72
+ ```bash
73
+ pip install .[full] # adds pathspec
74
+ ```
75
+
76
+ Requires **Python 3.9+**. Nothing else.
77
+
78
+ ## Use
79
+
80
+ ```bash
81
+ codebread --path /path/to/project # scan + open the UI in your browser
82
+ codebread # prompts for the path
83
+ python codebread.py --path . # uninstalled, same thing
84
+ ```
85
+
86
+ That's the whole quick start: point it at a folder, a browser tab opens with
87
+ the map already scanned.
88
+
89
+ ### CLI reference
90
+
91
+ | Flag | What it does |
92
+ |---|---|
93
+ | `--path, -p PATH` | root folder to scan (prompted if omitted) |
94
+ | `--port 8137` | local server port (auto-picks a free one nearby if taken) |
95
+ | `--json out.json` | export the full graph as JSON |
96
+ | `--load out.json` | re-open a saved scan without re-scanning |
97
+ | `--html out.html` | export a **self-contained static HTML** file you can share |
98
+ | `--diff old.json new.json` | compare two saved scans and print what changed (files/functions/tables added, removed, changed) |
99
+ | `--no-open` | don't auto-open the browser |
100
+ | `--no-serve` | scan + export only, don't start the server |
101
+ | `--version` | print the installed version |
102
+
103
+ ---
104
+
105
+ ## What you get
106
+
107
+ - **Explorer sidebar** — the full folder tree, expandable like a file
108
+ explorer; every file tagged with its layer color.
109
+ - **Orbit layout (default)** — files float freely in space, spread apart so
110
+ connections stay untangled. Expand a file and its functions arrange in a
111
+ clean ring around it, spoked by straight lines back to the center. A
112
+ **Free** force-directed layout is also available (toggle bottom-right).
113
+ - **Focus mode** — clears the canvas so you inspect one file at a time:
114
+ pick a file in the Explorer and only it, its functions, and its direct
115
+ connections show up. Toggle it off to go back to the full overview.
116
+ - **Progressive reveal (OSINT-style)** — click a file to slice it open into
117
+ its numbered functions; click a function to draw in what it calls and
118
+ what calls it. Dense codebases stay readable.
119
+ - **Full-chain highlight** — select any node and its complete end-to-end
120
+ chain lights up (frontend `fetch()` → `GET /api/users` route → handler →
121
+ `users` table), everything unrelated dims.
122
+ - **Right-click for actions** — a context menu on every node, edge, and
123
+ the empty canvas: reveal connections, focus a file, open it in the IDE
124
+ view, jump to a route's source/target, copy a name or path, and more.
125
+ - **Insights panel** — flags orphaned functions (no detected callers) and
126
+ circular call chains, both clickable to jump straight to them.
127
+ - **Diff mode** — compare two saved scans (`--diff old.json new.json`) to
128
+ see exactly what changed between them.
129
+ - **Minimap + breadcrumb** — a live minimap of the whole graph with a
130
+ draggable viewport, and a breadcrumb showing the real folder path of
131
+ whatever's currently selected.
132
+ - **Keyboard navigation** — `←`/`→` step through a selected node's
133
+ neighbors, `↑`/`↓` walk back/forward through your selection history,
134
+ `/` to search.
135
+ - **Detail panel** — params, return type, auto-generated description
136
+ ("Function 3 · handles GET /api/users · queries users"), every caller and
137
+ callee, clickable.
138
+ - **View the actual code** — every function has an expandable
139
+ **▸ View code** section: syntax-highlighted source with real line
140
+ numbers. A full **IDE view** (⌗) opens any file whole, with an outline
141
+ sidebar.
142
+ - **Search** (`/`) and **layer filter** (Frontend / Backend / Database /
143
+ Config) in the header.
144
+ - **Warnings, never silence** — unreadable files, unsupported languages and
145
+ permission problems show up as ⚠ badges and in the warnings list, never
146
+ hidden. Secrets found in config files are always masked.
147
+
148
+ ## Language support
149
+
150
+ | Language | Parser | Extracted |
151
+ |---|---|---|
152
+ | Python | stdlib `ast` (precise) | functions, classes, params/annotations, docstrings, Flask/FastAPI/Django routes, SQLAlchemy/Django models, raw SQL, `requests`/`httpx` calls |
153
+ | JavaScript / TypeScript / JSX / TSX / Vue / Svelte | structural regex + brace matching | functions, arrow fns, classes, Express/Nest/Fastify routes, `fetch`/`axios` calls, Mongoose/Prisma/Sequelize/Knex/TypeORM, raw SQL |
154
+ | Java, C#, Go, PHP, Ruby | structural regex | functions/methods, classes, Spring/ASP.NET/Laravel/Rails/Gin routes, raw SQL |
155
+ | SQL | regex | `CREATE TABLE` schemas with columns |
156
+ | Config (`.env`, json/yaml/toml/ini, settings.py…) | key scan | DB connection settings — **credentials always masked** |
157
+ | Anything else (Rust, Kotlin, Swift, C/C++…) | — | shown in the UI as "⚠ Unsupported — parsing skipped", never silently dropped |
158
+
159
+ ## How it classifies layers
160
+
161
+ Score-based heuristics combining framework import signatures
162
+ (React/Vue → frontend, Flask/Express → backend, SQLAlchemy/Prisma →
163
+ database), folder conventions (`/client`, `/server`, `/models`…), file
164
+ extensions, and extracted facts (defines routes → backend, defines models →
165
+ database). Ambiguous files are marked **Unclassified** instead of guessed.
166
+
167
+ ## How orphan + cycle detection works
168
+
169
+ - **Orphaned functions**: any function/method with zero detected incoming
170
+ calls, that isn't a route handler and isn't a common framework entry
171
+ point (`__init__`, `main`, `setUp`, test functions, …). Flagged with a
172
+ badge on the node and listed in the Insights panel — a good starting
173
+ point for finding dead code (heuristic, not exhaustive: it can miss calls
174
+ the static parser doesn't recognize).
175
+ - **Circular call chains**: an iterative cycle-detection pass over the
176
+ call graph (no recursion, so it's safe on large codebases) flags
177
+ functions that call each other in a loop, both on the node (↻ badge) and
178
+ as a listed chain in the Insights panel.
179
+
180
+ ## Project layout
181
+
182
+ ```
183
+ codebread.py ← runnable entry point (no install needed)
184
+ codebread/
185
+ cli.py ← argparse CLI
186
+ scanner.py ← .gitignore-aware recursive walker
187
+ languages.py ← language detection / binary sniffing
188
+ parsers/
189
+ python_parser.py ← ast-based Python extractor
190
+ javascript_parser.py ← JS/TS/Vue/Svelte extractor
191
+ generic_parser.py ← Java/C#/Go/PHP/Ruby + SQL + config
192
+ classifier.py ← frontend/backend/database/config scoring
193
+ connections.py ← call graph + API↔route + fn↔table matching +
194
+ orphan/cycle detection
195
+ analyzer.py ← pipeline orchestration
196
+ diff.py ← compares two saved scans
197
+ server.py ← stdlib local web server
198
+ export.py ← JSON + single-file HTML export
199
+ web/ ← the UI (vanilla JS + SVG, zero dependencies)
200
+ assets/ ← logo (.svg source + .png for the README —
201
+ GitHub blocks same-repo SVG <img> embeds)
202
+ ```
203
+
204
+ ---
205
+
206
+ ## Roadmap
207
+
208
+ Already done as of v1.0:
209
+
210
+ - [x] Orphaned-function and circular-dependency detection
211
+ - [x] Diff mode between two scans
212
+ - [x] Focus mode, orbit layout, right-click actions, minimap, breadcrumb
213
+
214
+ Not yet, but planned:
215
+
216
+ - [ ] "Explain this function" — a plain-language AI summary button
217
+ - [ ] More precise multi-language parsing (currently structural regex for
218
+ everything but Python)
219
+ - [ ] An automated test suite
220
+
221
+ Have an idea? Open an issue.
222
+
223
+ ## Contributing
224
+
225
+ This is a young, actively-changing personal project, so keep that in mind —
226
+ but contributions are genuinely welcome:
227
+
228
+ - **Bugs / ideas** → open an issue with a repro or a description.
229
+ - **Pull requests** → welcome, especially for language parser improvements
230
+ or UI polish. Keep the zero-dependency philosophy: the core tool should
231
+ keep running on nothing but the Python standard library, and the UI
232
+ should keep running on vanilla JS with no build step.
233
+ - No formal test suite yet, so please describe how you manually verified a
234
+ change in your PR.
235
+
236
+ ## License
237
+
238
+ [MIT](LICENSE) — use it, modify it, ship it, sell it. No attribution
239
+ required beyond keeping the license file. See [LICENSE](LICENSE) for the
240
+ full text.
@@ -0,0 +1,3 @@
1
+ """CodeBread — slice open a codebase and see its internal structure."""
2
+
3
+ __version__ = "1.0.0"
@@ -0,0 +1,84 @@
1
+ """Orchestrates: scan -> parse -> classify -> connect -> graph dict."""
2
+ from __future__ import annotations
3
+
4
+ import datetime
5
+ import os
6
+ import sys
7
+ from typing import Callable, Dict, Optional
8
+
9
+ from . import __version__
10
+ from .classifier import classify
11
+ from .connections import build_graph
12
+ from .parsers import parse_file
13
+ from .scanner import read_text, scan
14
+
15
+
16
+ def analyze(root: str,
17
+ progress: Optional[Callable[[str], None]] = None) -> Dict:
18
+ """Run the full pipeline on `root` and return the graph dict."""
19
+ say = progress or (lambda msg: None)
20
+ root = os.path.abspath(root)
21
+
22
+ say(f"Scanning {root} ...")
23
+ result = scan(root)
24
+ files_meta = result["files"]
25
+ warnings = result["warnings"]
26
+ say(f" found {len(files_meta)} scannable files")
27
+
28
+ parsed = []
29
+ unsupported = {}
30
+ for i, meta in enumerate(files_meta, 1):
31
+ text, err = read_text(meta["abspath"])
32
+ info = parse_file(meta["path"], text, meta["language"])
33
+ if err:
34
+ info.warnings.append(err)
35
+ info.layer = classify(info, text)
36
+ if info.parsed or info.language in ("html", "css"):
37
+ info.source = text if len(text) <= 300_000 else \
38
+ text[:300_000] + "\n… (truncated)"
39
+ parsed.append(info)
40
+ for w in info.warnings:
41
+ if w.startswith("Unsupported:"):
42
+ unsupported.setdefault(meta["language"], 0)
43
+ unsupported[meta["language"]] += 1
44
+ warnings.append({"path": meta["path"], "message": w})
45
+ if i % 50 == 0:
46
+ say(f" parsed {i}/{len(files_meta)} files")
47
+
48
+ for lang, count in sorted(unsupported.items()):
49
+ say(f" note: {count} file(s) in {lang} - no parser available, "
50
+ f"shown as unsupported in the UI")
51
+
52
+ say("Mapping connections ...")
53
+ _annotate_tree(result["tree"], {f.path: f for f in parsed})
54
+ graph = build_graph(parsed, result["tree"], warnings)
55
+ graph["meta"] = {
56
+ "root": root,
57
+ "name": os.path.basename(root) or root,
58
+ "scannedAt": datetime.datetime.now().isoformat(timespec="seconds"),
59
+ "version": __version__,
60
+ }
61
+ s = graph["stats"]
62
+ say(f"Done: {s['files']} files, {s['functions']} functions, "
63
+ f"{s['tables']} tables, {s['connections']} connections, "
64
+ f"{s['warnings']} warnings")
65
+ return graph
66
+
67
+
68
+ def _annotate_tree(node: Dict, by_path: Dict) -> None:
69
+ """Copy layer/warning info onto tree nodes for the sidebar."""
70
+ if node.get("type") == "file":
71
+ info = by_path.get(node.get("path"))
72
+ if info is not None:
73
+ node["layer"] = info.layer
74
+ node["nFunctions"] = len(info.functions)
75
+ if info.warnings and "warning" not in node:
76
+ node["warning"] = "parse"
77
+ return
78
+ layers = set()
79
+ for child in node.get("children", []):
80
+ _annotate_tree(child, by_path)
81
+ if child.get("layer") and child["layer"] not in ("unknown", None):
82
+ layers.add(child["layer"])
83
+ if len(layers) == 1:
84
+ node["layer"] = layers.pop()