serpentine-parser 0.1.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.
Files changed (50) hide show
  1. serpentine_parser-0.1.3/LICENCE +14 -0
  2. serpentine_parser-0.1.3/PKG-INFO +423 -0
  3. serpentine_parser-0.1.3/README.md +393 -0
  4. serpentine_parser-0.1.3/pyproject.toml +61 -0
  5. serpentine_parser-0.1.3/rust/CLAUDE.md +61 -0
  6. serpentine_parser-0.1.3/rust/Cargo.lock +459 -0
  7. serpentine_parser-0.1.3/rust/Cargo.toml +19 -0
  8. serpentine_parser-0.1.3/rust/src/events.rs +509 -0
  9. serpentine_parser-0.1.3/rust/src/graph/builder.rs +185 -0
  10. serpentine_parser-0.1.3/rust/src/graph/loaders.rs +918 -0
  11. serpentine_parser-0.1.3/rust/src/graph/mod.rs +251 -0
  12. serpentine_parser-0.1.3/rust/src/graph/pdg.rs +94 -0
  13. serpentine_parser-0.1.3/rust/src/graph/resolvers.rs +411 -0
  14. serpentine_parser-0.1.3/rust/src/javascript/config.rs +117 -0
  15. serpentine_parser-0.1.3/rust/src/javascript/mod.rs +1816 -0
  16. serpentine_parser-0.1.3/rust/src/lib.rs +381 -0
  17. serpentine_parser-0.1.3/rust/src/message_bus.rs +77 -0
  18. serpentine_parser-0.1.3/rust/src/python/config.rs +271 -0
  19. serpentine_parser-0.1.3/rust/src/python/mod.rs +1577 -0
  20. serpentine_parser-0.1.3/rust/src/rust_lang/config.rs +48 -0
  21. serpentine_parser-0.1.3/rust/src/rust_lang/mod.rs +1247 -0
  22. serpentine_parser-0.1.3/rust/src/subscribers/README.md +354 -0
  23. serpentine_parser-0.1.3/rust/src/subscribers/code_snippet.rs +182 -0
  24. serpentine_parser-0.1.3/rust/src/subscribers/definitions.rs +258 -0
  25. serpentine_parser-0.1.3/rust/src/subscribers/event_counter.rs +88 -0
  26. serpentine_parser-0.1.3/rust/src/subscribers/imports.rs +195 -0
  27. serpentine_parser-0.1.3/rust/src/subscribers/mod.rs +22 -0
  28. serpentine_parser-0.1.3/rust/src/subscribers/pdg.rs +977 -0
  29. serpentine_parser-0.1.3/rust/src/subscribers/raw_bindings.rs +659 -0
  30. serpentine_parser-0.1.3/rust/src/subscribers/scope_tree.rs +232 -0
  31. serpentine_parser-0.1.3/rust/src/subscribers/uses.rs +201 -0
  32. serpentine_parser-0.1.3/src/serpentine/__init__.py +36 -0
  33. serpentine_parser-0.1.3/src/serpentine/_analyzer.pyi +14 -0
  34. serpentine_parser-0.1.3/src/serpentine/cache.py +100 -0
  35. serpentine_parser-0.1.3/src/serpentine/cli.py +573 -0
  36. serpentine_parser-0.1.3/src/serpentine/config.py +147 -0
  37. serpentine_parser-0.1.3/src/serpentine/selector.py +440 -0
  38. serpentine_parser-0.1.3/src/serpentine/server/__init__.py +16 -0
  39. serpentine_parser-0.1.3/src/serpentine/server/app.py +264 -0
  40. serpentine_parser-0.1.3/src/serpentine/server/routes.py +241 -0
  41. serpentine_parser-0.1.3/src/serpentine/server/websocket.py +124 -0
  42. serpentine_parser-0.1.3/src/serpentine/state.py +511 -0
  43. serpentine_parser-0.1.3/src/serpentine/static/assets/elk-worker.min-BdOC9sib.js +6263 -0
  44. serpentine_parser-0.1.3/src/serpentine/static/assets/index-BsyBZio8.css +1 -0
  45. serpentine_parser-0.1.3/src/serpentine/static/assets/index-CpvmYCe_.js +219 -0
  46. serpentine_parser-0.1.3/src/serpentine/static/assets/layoutWorker-Dd3vNlDT.js +24 -0
  47. serpentine_parser-0.1.3/src/serpentine/static/assets/svgToPng-CCU1Oj7k.js +2 -0
  48. serpentine_parser-0.1.3/src/serpentine/static/index.html +13 -0
  49. serpentine_parser-0.1.3/src/serpentine/static/logo.svg +39 -0
  50. serpentine_parser-0.1.3/src/serpentine/watcher.py +201 -0
@@ -0,0 +1,14 @@
1
+
2
+ Copyright 2026 Christopher Garretty
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
@@ -0,0 +1,423 @@
1
+ Metadata-Version: 2.4
2
+ Name: serpentine-parser
3
+ Version: 0.1.3
4
+ Classifier: Development Status :: 4 - Beta
5
+ Classifier: Environment :: Console
6
+ Classifier: Environment :: Web Environment
7
+ Classifier: Intended Audience :: Developers
8
+ Classifier: License :: OSI Approved :: Apache Software License
9
+ Classifier: Operating System :: OS Independent
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.12
12
+ Classifier: Programming Language :: Rust
13
+ Classifier: Topic :: Software Development :: Quality Assurance
14
+ Classifier: Topic :: Utilities
15
+ Requires-Dist: watchdog>=6.0.0
16
+ Requires-Dist: click>=8.1.0
17
+ Requires-Dist: starlette>=0.38.0
18
+ Requires-Dist: uvicorn[standard]>=0.30.0
19
+ Requires-Dist: websockets>=12.0
20
+ License-File: LICENCE
21
+ Summary: Fast dependency graph analysis and visualization for Python, JavaScript/TypeScript, and Rust projects
22
+ Keywords: dependency-graph,visualization,static-analysis,python,javascript,rust,tree-sitter
23
+ Author: Christopher Garretty
24
+ Requires-Python: >=3.12
25
+ Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
26
+ Project-URL: Homepage, https://github.com/serpentine-parser/serpentine
27
+ Project-URL: Issues, https://github.com/serpentine-parser/serpentine/issues
28
+ Project-URL: Repository, https://github.com/serpentine-parser/serpentine
29
+
30
+ <p align="center">
31
+ <img src="frontend/public/logo.svg" alt="Serpentine" width="64" />
32
+ </p>
33
+
34
+ # Serpentine
35
+
36
+ Fast dependency graph analysis and visualization for Python, JavaScript/TypeScript, and Rust projects.
37
+
38
+ ![Serpentine UI](docs/screenshot.png)
39
+
40
+ Serpentine analyzes your codebase using a Rust-powered parser and displays an interactive dependency graph in your browser. It resolves dependencies down to the variable and call level and watches for file changes in real time.
41
+
42
+ ---
43
+
44
+ ## Features
45
+
46
+ - **Multi-language**: Python, JavaScript, TypeScript, and Rust
47
+ - **Deep resolution**: Resolves calls and type references, not just import edges
48
+ - **Interactive graph**: Expandable nodes, search, pan/zoom, collapsible modules
49
+ - **Real-time updates**: File watcher pushes changes via WebSocket
50
+ - **Agent-ready CLI**: Structured JSON output with selectors for use in AI agent workflows
51
+
52
+ ---
53
+
54
+ ## Installation
55
+
56
+ ### PyPI (recommended)
57
+
58
+ ```bash
59
+ pip install serpentine-parser
60
+ ```
61
+
62
+ Or with [uv](https://docs.astral.sh/uv/):
63
+
64
+ ```bash
65
+ uv tool install serpentine-parser
66
+ ```
67
+
68
+ ### From source
69
+
70
+ > **Prerequisites**: Python 3.12+, [Rust toolchain](https://rustup.rs), Node.js 18+
71
+
72
+ ```bash
73
+ git clone https://github.com/serpentine-parser/serpentine.git
74
+ cd serpentine
75
+
76
+ # 1. Build the frontend
77
+ cd frontend && npm install && npm run build && cd ..
78
+
79
+ # 2. Build the Rust extension and install the CLI
80
+ make install
81
+ ```
82
+
83
+ This installs the `serpentine` CLI globally via `uv tool`, which you will need to [install separately](https://docs.astral.sh/uv/getting-started/installation/).
84
+
85
+ ---
86
+
87
+ ## Quick Start
88
+
89
+ Navigate to any Python, JavaScript/TypeScript, or Rust project and run:
90
+
91
+ ```bash
92
+ serpentine serve
93
+ ```
94
+
95
+ Serpentine will analyze the project, start a local server at `http://127.0.0.1:8765`, and open the visualization in your browser. File changes are detected automatically and the graph updates in real time.
96
+
97
+ ---
98
+
99
+ ## CLI Reference
100
+
101
+ ### `serpentine serve`
102
+
103
+ Start the visualization server with live file watching.
104
+
105
+ ```
106
+ serpentine serve [PATH] [OPTIONS]
107
+
108
+ Arguments:
109
+ PATH Directory to analyze (default: current directory)
110
+
111
+ Options:
112
+ -p, --port INT Port to run the server on (default: 8765)
113
+ -h, --host TEXT Host to bind to (default: 127.0.0.1)
114
+ --no-browser Don't open browser automatically
115
+ --no-watch Disable file watching (static analysis only)
116
+ ```
117
+
118
+ ### `serpentine analyze`
119
+
120
+ Analyze a project and output the full dependency graph as JSON.
121
+
122
+ ```
123
+ serpentine analyze [PATH] [OPTIONS]
124
+
125
+ Options:
126
+ -o, --output PATH Write output to file instead of stdout
127
+ --pretty Pretty-print JSON
128
+ --select TEXT Selector expression to filter nodes (see below)
129
+ --exclude TEXT Exclusion pattern (same syntax as --select)
130
+ --no-cfg Strip control-flow graph data from nodes
131
+ --edges-only Output only the edges array (compact)
132
+ --include-standard Include stdlib nodes (default: off)
133
+ --include-third-party Include third-party nodes (default: off)
134
+ --state TEXT Filter by change state: modified,added,deleted
135
+ ```
136
+
137
+ ### `serpentine catalog`
138
+
139
+ Flat list of all nodes — useful for discovering node IDs before building selectors.
140
+
141
+ ```
142
+ serpentine catalog [PATH] [OPTIONS]
143
+
144
+ Options:
145
+ --filter TEXT Glob pattern matched against node id and name
146
+ (repeatable; multiple patterns = union)
147
+ --no-assignments Exclude variable/assignment nodes
148
+ -o, --output PATH Write output to file instead of stdout
149
+ --pretty Pretty-print JSON
150
+ --include-standard Include stdlib nodes
151
+ --include-third-party Include third-party nodes
152
+ ```
153
+
154
+ ### `serpentine stats`
155
+
156
+ Quick summary of project scale: node/edge counts by type and origin.
157
+
158
+ ```
159
+ serpentine stats [PATH] [OPTIONS]
160
+
161
+ Options:
162
+ --pretty Pretty-print JSON
163
+ --include-standard Include stdlib nodes
164
+ --include-third-party Include third-party nodes
165
+ ```
166
+
167
+ ---
168
+
169
+ ## Querying the Graph
170
+
171
+ `serpentine analyze` and `serpentine catalog` accept `--select` and `--exclude` to slice the graph down to just the nodes you care about. This is useful for large codebases where the full graph is too noisy, or for piping results into other tools.
172
+
173
+ ### Step 1 — Find your node IDs
174
+
175
+ Every node has a dotted ID that reflects its location in the codebase. Use `catalog` to discover them:
176
+
177
+ ```bash
178
+ serpentine catalog . --no-assignments --pretty
179
+ ```
180
+
181
+ This outputs a flat list of every module, class, and function with its ID:
182
+
183
+ ```json
184
+ {
185
+ "nodes": [
186
+ { "id": "src.auth.models.User", "name": "User", "type": "class", ... },
187
+ { "id": "src.auth.views.login", "name": "login", "type": "function", ... },
188
+ { "id": "src.payments.stripe.charge", "name": "charge", "type": "function", ... }
189
+ ]
190
+ }
191
+ ```
192
+
193
+ Narrow it down with `--filter` (glob matched against both ID and name):
194
+
195
+ ```bash
196
+ # Find everything related to auth
197
+ serpentine catalog . --filter "*auth*" --no-assignments --pretty
198
+
199
+ # Find by name across modules
200
+ serpentine catalog . --filter "*User*" --no-assignments --pretty
201
+ ```
202
+
203
+ ### Step 2 — Select nodes and their dependencies
204
+
205
+ Once you have IDs, use `--select` with `serpentine analyze`. The selector controls which nodes (and their relationships) appear in the output.
206
+
207
+ **Plain pattern** — just the matching nodes:
208
+
209
+ ```bash
210
+ serpentine analyze --select "src.auth.*" --no-cfg --pretty
211
+ ```
212
+
213
+ **`+pattern`** — the matching nodes _plus everything they depend on_ (upstream):
214
+
215
+ ```bash
216
+ # What does the login view need to work?
217
+ serpentine analyze --select "+src.auth.views.login" --no-cfg --pretty
218
+ ```
219
+
220
+ **`pattern+`** — the matching nodes _plus everything that depends on them_ (downstream):
221
+
222
+ ```bash
223
+ # What breaks if I change the User model?
224
+ serpentine analyze --select "src.auth.models.User+" --no-cfg --pretty
225
+ ```
226
+
227
+ **`+pattern+`** — both directions (full blast radius):
228
+
229
+ ```bash
230
+ serpentine analyze --select "+src.payments.*+" --no-cfg --pretty
231
+ ```
232
+
233
+ **`@pattern`** — the full connected component (everything reachable in any direction):
234
+
235
+ ```bash
236
+ serpentine analyze --select "@src.auth.*" --no-cfg --pretty
237
+ ```
238
+
239
+ **Bounded hops** — limit how many levels to traverse:
240
+
241
+ ```bash
242
+ # 2 levels of dependencies upstream, 1 level downstream
243
+ serpentine analyze --select "2+src.auth.views.login+1" --no-cfg --pretty
244
+ ```
245
+
246
+ **Multiple selectors** — comma-separated, combined as a union:
247
+
248
+ ```bash
249
+ serpentine analyze --select "+src.auth.*,+src.payments.*" --no-cfg --pretty
250
+ ```
251
+
252
+ ### Step 3 — Exclude noise
253
+
254
+ `--exclude` removes nodes from the result (including their descendants):
255
+
256
+ ```bash
257
+ # Show auth and its deps, but skip test files
258
+ serpentine analyze --select "+src.auth.*" --exclude "*test*" --no-cfg --pretty
259
+ ```
260
+
261
+ ### Glob pattern rules
262
+
263
+ `*` in a selector matches any characters **including dots**, so it crosses module boundaries:
264
+
265
+ | You want | Use |
266
+ | ---------------------------------- | ------------ |
267
+ | All nodes whose ID contains "auth" | `*auth*` |
268
+ | All children of a specific module | `src.auth.*` |
269
+ | A class anywhere in the project | `*.User` |
270
+ | All test files | `*test*` |
271
+
272
+ > **Tip**: `**` is equivalent to `*` — both match across dots.
273
+
274
+ ### Compact output for large graphs
275
+
276
+ Use `--edges-only` to get just the edge list (much smaller than the full node tree):
277
+
278
+ ```bash
279
+ serpentine analyze --select "+src.auth.*+" --edges-only --pretty
280
+ ```
281
+
282
+ Each edge has a `from` and `to` field with node IDs, and a `type` field (`calls`, `is-a`, or `has-a`).
283
+
284
+ ---
285
+
286
+ ## Configuration
287
+
288
+ Serpentine looks for `.serpentine.yml` or `serpentine.yml` in the project root. All settings are optional.
289
+
290
+ ```yaml
291
+ analysis:
292
+ # File extensions to analyze (default: all supported)
293
+ extensions: [".py", ".js", ".jsx", ".ts", ".tsx", ".rs"]
294
+
295
+ # Directories to skip
296
+ exclude_dirs:
297
+ - node_modules
298
+ - .venv
299
+ - dist
300
+ - build
301
+
302
+ # Glob patterns for files to skip
303
+ exclude_patterns:
304
+ - "**/*.test.ts"
305
+ - "**/generated/**"
306
+ ```
307
+
308
+ ---
309
+
310
+ ## Using Serpentine with AI Agents
311
+
312
+ Serpentine's CLI is designed to be consumed by AI coding agents (Claude, Cursor, Copilot, etc.). The structured JSON output, selector syntax, and `--edges-only` / `--no-assignments` flags exist specifically to give agents precise, low-noise subgraphs without requiring file reads.
313
+
314
+ ### The problem it solves
315
+
316
+ When an agent starts a non-trivial task, it faces a cold-start problem: it doesn't know which files are relevant, how components relate, or what the blast radius of a change might be. The usual approach — grep, glob, read files one at a time — is expensive in tokens and often incomplete.
317
+
318
+ Serpentine collapses that exploration into 2-3 CLI calls. The agent gets a structural picture of the relevant code _before_ it starts reading files or writing a plan. In practice this means:
319
+
320
+ - Plans are scoped to the right files and boundaries from the start
321
+ - Less back-and-forth between reading files to trace call chains
322
+ - Fewer surprises mid-implementation when a dependency was missed
323
+
324
+ ### Recommended workflow for agents
325
+
326
+ ```bash
327
+ # 1. Get the lay of the land — module names, rough scale
328
+ serpentine stats .
329
+
330
+ # 2. Find relevant node IDs by name
331
+ serpentine catalog . --filter "*auth*" --no-assignments --pretty
332
+
333
+ # 3. Get the subgraph for the relevant area
334
+ serpentine analyze . --select "+src.auth.*+" --no-cfg --edges-only --pretty
335
+ ```
336
+
337
+ Read the edges to understand what connects to what, then read only the files that are actually relevant.
338
+
339
+ ### Scenarios where this pays off
340
+
341
+ **Before refactoring a module**
342
+ Use `--select "module+"` to map everything that depends on the module before writing a plan. This ensures the plan accounts for every callsite and doesn't discover new dependents halfway through.
343
+
344
+ **Before adding a feature that spans modules**
345
+ Use `--select "+moduleA.*,+moduleB.*"` to get the combined subgraph of two areas and understand exactly where they intersect. The boundaries of the work become clear before any code is written.
346
+
347
+ **Orienting to an unfamiliar codebase**
348
+ `serpentine stats` gives you the top-level module list and scale. `serpentine catalog . --no-assignments` gives a flat index of every class and function. Together these give structural orientation without reading a single file.
349
+
350
+ **Before deleting code**
351
+ Use `--select "*.TargetFunction+"` to get all downstream dependents. An empty result confirms the code is truly unused.
352
+
353
+ **Tracing a call chain**
354
+ Use `--select "+*.entrypoint+3"` to get 3 hops downstream from an entry point and understand the execution path before adding instrumentation or fixing a bug.
355
+
356
+ ### Claude Code skill
357
+
358
+ This repository includes a Claude Code skill at `.claude/commands/serpentine.md`. If you're using Claude Code in a project analyzed by Serpentine, you can copy this file into your project's `.claude/commands/` directory. It instructs Claude to use Serpentine as its first step before reading files or grepping — running `stats`, then `catalog`, then `analyze` in sequence before answering structural questions or planning changes.
359
+
360
+ ---
361
+
362
+ ## Development
363
+
364
+ ### Project Structure
365
+
366
+ ```
367
+ serpentine/
368
+ ├── rust/ # Rust analyzer (tree-sitter + PyO3)
369
+ │ └── src/
370
+ │ ├── lib.rs # PyO3 module entry point
371
+ │ ├── python/ # Python parser
372
+ │ ├── javascript/ # JS/TS parser
373
+ │ ├── rust_lang/ # Rust parser
374
+ │ ├── subscribers/ # Event processors (imports, calls, defs)
375
+ │ └── graph/ # Graph builder and resolvers
376
+ ├── src/serpentine/ # Python package
377
+ │ ├── cli.py # CLI commands
378
+ │ ├── state.py # Graph state management
379
+ │ ├── watcher.py # File watcher
380
+ │ ├── selector.py # Graph selector engine
381
+ │ ├── config.py # Config loading
382
+ │ └── server/ # Starlette web server + WebSocket
383
+ ├── frontend/ # React frontend (Vite + TypeScript)
384
+ │ └── src/
385
+ ├── Makefile # Build targets
386
+ └── pyproject.toml
387
+ ```
388
+
389
+ ### Building for Development
390
+
391
+ [Tilt](https://tilt.dev) is recommended for development — it rebuilds the Rust extension and frontend in parallel when files change:
392
+
393
+ ```bash
394
+ tilt up
395
+ ```
396
+
397
+ Or manually:
398
+
399
+ ```bash
400
+ # Build Rust extension (rerun after changes to rust/src/)
401
+ uv run maturin develop
402
+
403
+ # Build frontend (rerun after changes to frontend/src/)
404
+ cd frontend && npm run build
405
+
406
+ # Run server
407
+ uv run serpentine serve --no-browser
408
+ ```
409
+
410
+ ### Adding a Language
411
+
412
+ 1. Create a parser module in `rust/src/<language>/`
413
+ 2. Emit `ImportStatement`, `UseName`, and `CallExpression` events via the message bus
414
+ 3. Register the parser in `rust/src/lib.rs`
415
+
416
+ See `rust/src/python/` for a complete reference implementation and `CONTRIBUTING.md` for full details.
417
+
418
+ ---
419
+
420
+ ## License
421
+
422
+ [Apache 2.0](LICENCE)
423
+