codingest 0.1.5__tar.gz → 0.1.7__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.
- {codingest-0.1.5 → codingest-0.1.7}/Cargo.lock +8 -8
- {codingest-0.1.5 → codingest-0.1.7}/Cargo.toml +9 -5
- {codingest-0.1.5 → codingest-0.1.7}/PKG-INFO +9 -5
- {codingest-0.1.5 → codingest-0.1.7}/README.md +7 -3
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/Cargo.toml +1 -1
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/bin/codingest_bench.rs +5 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/bin/codingest_stats.rs +166 -24
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/builder/call_edges.rs +194 -19
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/builder/load/entity_frames.rs +34 -1
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/builder/other_edges.rs +140 -15
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/builder/routes/django.rs +136 -11
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/docs/mod.rs +255 -29
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/parsers/python.rs +726 -2
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/parsers/shared.rs +88 -1
- codingest-0.1.7/crates/codingest/src/parsers/typescript.rs +2764 -0
- codingest-0.1.7/crates/codingest/tests/goldens/README.md +146 -0
- codingest-0.1.7/crates/codingest/tests/goldens/docs_mdx.sha256 +1 -0
- codingest-0.1.7/crates/codingest/tests/goldens/py_nested_defs.sha256 +1 -0
- codingest-0.1.7/crates/codingest/tests/goldens/ts_closure_scope.sha256 +1 -0
- codingest-0.1.7/crates/codingest/tests/goldens/ts_hof_binding.sha256 +1 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/tests/parity.rs +42 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-cli/Cargo.toml +1 -1
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-mcp/Cargo.toml +1 -1
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-py/Cargo.toml +3 -3
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-py/src/lib.rs +1 -1
- {codingest-0.1.5 → codingest-0.1.7}/pyproject.toml +2 -2
- codingest-0.1.5/crates/codingest/src/parsers/typescript.rs +0 -1281
- codingest-0.1.5/crates/codingest/tests/goldens/README.md +0 -80
- {codingest-0.1.5 → codingest-0.1.7}/LICENSE +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/codingest/__init__.py +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/codingest/__init__.pyi +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/codingest/cli.py +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/codingest/mcp_server.py +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/builder/js_workspace.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/builder/load/edge_frames.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/builder/load.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/builder/mod.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/builder/routes/fastapi.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/builder/routes/flask.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/builder/routes/mod.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/builder/semantic_edges.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/builder/type_edges.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/cross_lang.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/docs/rst.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/lib.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/manifest/mod.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/models.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/parsers/agc.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/parsers/cpp.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/parsers/csharp.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/parsers/css.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/parsers/dart.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/parsers/go.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/parsers/html.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/parsers/java.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/parsers/mod.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/parsers/php.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/parsers/registry.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/parsers/rust_lang.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/parsers/swift.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/repo.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/src/rev.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/tests/agc_apollo.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/tests/goldens/agc_basic.sha256 +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/tests/goldens/cross_ts_py.sha256 +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/tests/goldens/dup_minified_assets.sha256 +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/tests/goldens/py_basic.sha256 +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/tests/goldens/py_inheritance.sha256 +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/tests/goldens/rust_xfile.sha256 +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/tests/goldens/ts_callback.sha256 +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest/tests/goldens/ts_monorepo.sha256 +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-cli/skills/codingest-code-review/SKILL.md +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-cli/skills/codingest-code-review/references/mcp-upgrade.md +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-cli/skills/codingest-code-review/references/public-repositories.md +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-cli/skills/codingest-code-review/references/queries.md +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-cli/src/code_tree_cli.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-cli/src/lib.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-cli/src/main.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-cli/src/query.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-cli/src/skill.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-cli/src/skill_assets.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-cli/tests/exit_codes.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-mcp/src/lib.rs +0 -0
- {codingest-0.1.5 → codingest-0.1.7}/crates/codingest-mcp/src/main.rs +0 -0
|
@@ -313,7 +313,7 @@ dependencies = [
|
|
|
313
313
|
|
|
314
314
|
[[package]]
|
|
315
315
|
name = "codingest"
|
|
316
|
-
version = "0.1.
|
|
316
|
+
version = "0.1.7"
|
|
317
317
|
dependencies = [
|
|
318
318
|
"aho-corasick",
|
|
319
319
|
"base64",
|
|
@@ -345,7 +345,7 @@ dependencies = [
|
|
|
345
345
|
|
|
346
346
|
[[package]]
|
|
347
347
|
name = "codingest-cli"
|
|
348
|
-
version = "0.1.
|
|
348
|
+
version = "0.1.7"
|
|
349
349
|
dependencies = [
|
|
350
350
|
"anyhow",
|
|
351
351
|
"clap",
|
|
@@ -357,7 +357,7 @@ dependencies = [
|
|
|
357
357
|
|
|
358
358
|
[[package]]
|
|
359
359
|
name = "codingest-mcp"
|
|
360
|
-
version = "0.1.
|
|
360
|
+
version = "0.1.7"
|
|
361
361
|
dependencies = [
|
|
362
362
|
"anyhow",
|
|
363
363
|
"codingest",
|
|
@@ -366,7 +366,7 @@ dependencies = [
|
|
|
366
366
|
|
|
367
367
|
[[package]]
|
|
368
368
|
name = "codingest-py"
|
|
369
|
-
version = "0.1.
|
|
369
|
+
version = "0.1.7"
|
|
370
370
|
dependencies = [
|
|
371
371
|
"codingest",
|
|
372
372
|
"codingest-cli",
|
|
@@ -1393,9 +1393,9 @@ dependencies = [
|
|
|
1393
1393
|
|
|
1394
1394
|
[[package]]
|
|
1395
1395
|
name = "kglite"
|
|
1396
|
-
version = "0.15.
|
|
1396
|
+
version = "0.15.6"
|
|
1397
1397
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1398
|
-
checksum = "
|
|
1398
|
+
checksum = "a8cf3016156af6dafbc1041fa443e94002686b6deeee0fea38f9b712c50c96f8"
|
|
1399
1399
|
dependencies = [
|
|
1400
1400
|
"bzip2",
|
|
1401
1401
|
"chrono",
|
|
@@ -1428,9 +1428,9 @@ dependencies = [
|
|
|
1428
1428
|
|
|
1429
1429
|
[[package]]
|
|
1430
1430
|
name = "kglite-mcp-server"
|
|
1431
|
-
version = "0.15.
|
|
1431
|
+
version = "0.15.6"
|
|
1432
1432
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1433
|
-
checksum = "
|
|
1433
|
+
checksum = "afaf8e38626f3991d7d7fca93df9230ec7160af894e855bc5cbe49e6c0342ab3"
|
|
1434
1434
|
dependencies = [
|
|
1435
1435
|
"anyhow",
|
|
1436
1436
|
"bytes",
|
|
@@ -3,7 +3,7 @@ members = ["crates/codingest", "crates/codingest-cli", "crates/codingest-mcp", "
|
|
|
3
3
|
resolver = "2"
|
|
4
4
|
|
|
5
5
|
[workspace.package]
|
|
6
|
-
version = "0.1.
|
|
6
|
+
version = "0.1.7"
|
|
7
7
|
edition = "2021"
|
|
8
8
|
rust-version = "1.88"
|
|
9
9
|
license = "MIT"
|
|
@@ -12,8 +12,12 @@ repository = "https://github.com/kkollsga/codingest"
|
|
|
12
12
|
[workspace.dependencies]
|
|
13
13
|
base64 = "0.22"
|
|
14
14
|
sha2 = "0.11"
|
|
15
|
-
# kglite engine + MCP server — imported as crates.io libraries. The 0.15.
|
|
16
|
-
# floor
|
|
15
|
+
# kglite engine + MCP server — imported as crates.io libraries. The 0.15.6
|
|
16
|
+
# floor fixes mixed-selection vector dispatch, mixed-metric exact search,
|
|
17
|
+
# community-detection modularity scoring, sampled-centrality validation, and
|
|
18
|
+
# persisted HNSW validation, while adding the bulk node-degree primitive and
|
|
19
|
+
# graph-algorithm/vector-search performance improvements. It builds on the two
|
|
20
|
+
# workspace controls codingest asked upstream for in 0.15.5:
|
|
17
21
|
# `workspace.sandbox_root`, a real containment boundary that confines
|
|
18
22
|
# `set_root_dir` to a subtree instead of trusting the caller's path, and
|
|
19
23
|
# `workspace.adopt_client_roots`. Both land on top of the generic
|
|
@@ -25,8 +29,8 @@ sha2 = "0.11"
|
|
|
25
29
|
# and no disk storage. Neither patch changes `kglite::api`, graph output,
|
|
26
30
|
# property encoding, or `.kgl` serialization.
|
|
27
31
|
# Keep both libraries aligned so the graph and server share one engine release.
|
|
28
|
-
kglite = { version = "0.15.
|
|
29
|
-
kglite-mcp-server = { version = "0.15.
|
|
32
|
+
kglite = { version = "0.15.6", default-features = false }
|
|
33
|
+
kglite-mcp-server = { version = "0.15.6", default-features = false }
|
|
30
34
|
|
|
31
35
|
# Mirror KGLite's release codegen so the standalone builder has
|
|
32
36
|
# performance parity with the in-tree component (see KGLite
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: codingest
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.7
|
|
4
4
|
Classifier: Development Status :: 3 - Alpha
|
|
5
5
|
Classifier: Intended Audience :: Developers
|
|
6
6
|
Classifier: Programming Language :: Python :: 3
|
|
@@ -12,7 +12,7 @@ Classifier: Programming Language :: Python :: 3.14
|
|
|
12
12
|
Classifier: Programming Language :: Rust
|
|
13
13
|
Classifier: Topic :: Software Development
|
|
14
14
|
Classifier: Topic :: Software Development :: Libraries
|
|
15
|
-
Requires-Dist: kglite>=0.15.
|
|
15
|
+
Requires-Dist: kglite>=0.15.6,<0.16
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Summary: Build fast, queryable code graphs for AI agents, MCP code review, and local or GitHub repository analysis.
|
|
18
18
|
Keywords: ai-agents,mcp,code-review,knowledge-graph,code-analysis,github,tree-sitter,cypher
|
|
@@ -60,6 +60,10 @@ a real `kglite.KnowledgeGraph`, ready for Cypher queries.
|
|
|
60
60
|
|
|
61
61
|
- **Agent-ready MCP:** give an MCP client `graph_overview`, `cypher_query`,
|
|
62
62
|
`read_code_source`, repository switching, and automatic graph refresh.
|
|
63
|
+
[opencode is set up and verified end to end](https://codingest.readthedocs.io/en/latest/mcp.html#using-codingest-mcp-with-opencode)
|
|
64
|
+
— including a config that needs no absolute paths — and `codingest skill
|
|
65
|
+
install` packages the review skill for Claude Code and Codex, which opencode
|
|
66
|
+
also discovers with no extra step.
|
|
63
67
|
- **Fast local review:** map definitions, callers, dependencies, routes,
|
|
64
68
|
inheritance, and affected tests without uploading or executing the project.
|
|
65
69
|
- **Open-source intelligence:** clone and analyse a GitHub repository with one
|
|
@@ -187,7 +191,7 @@ codingest skill install # code-review Agent Skill
|
|
|
187
191
|
```
|
|
188
192
|
|
|
189
193
|
The wheel bundles every grammar plus the `codingest` and `codingest-mcp`
|
|
190
|
-
commands. KGLite ≥0.15.
|
|
194
|
+
commands. KGLite ≥0.15.6 is installed automatically as the query/storage
|
|
191
195
|
engine; its MCP server and the transitive `mcp-methods` framework power the
|
|
192
196
|
builder-aware Codingest server. Nothing else needs to be installed.
|
|
193
197
|
|
|
@@ -200,7 +204,7 @@ Python prerequisites.
|
|
|
200
204
|
```toml
|
|
201
205
|
[dependencies]
|
|
202
206
|
codingest = "0.1"
|
|
203
|
-
kglite = "0.15.
|
|
207
|
+
kglite = "0.15.6"
|
|
204
208
|
```
|
|
205
209
|
|
|
206
210
|
```rust
|
|
@@ -272,7 +276,7 @@ diagnostic.
|
|
|
272
276
|
## Dependency policy
|
|
273
277
|
|
|
274
278
|
`kglite` and `kglite-mcp-server` use matching crates.io requirements with a
|
|
275
|
-
0.15.
|
|
279
|
+
0.15.6 minimum and a shared lockfile. This keeps the builder, persistence
|
|
276
280
|
handoff, and embedded MCP server on one compatible engine patch line.
|
|
277
281
|
|
|
278
282
|
## Parity with the (now-removed) in-tree component
|
|
@@ -33,6 +33,10 @@ a real `kglite.KnowledgeGraph`, ready for Cypher queries.
|
|
|
33
33
|
|
|
34
34
|
- **Agent-ready MCP:** give an MCP client `graph_overview`, `cypher_query`,
|
|
35
35
|
`read_code_source`, repository switching, and automatic graph refresh.
|
|
36
|
+
[opencode is set up and verified end to end](https://codingest.readthedocs.io/en/latest/mcp.html#using-codingest-mcp-with-opencode)
|
|
37
|
+
— including a config that needs no absolute paths — and `codingest skill
|
|
38
|
+
install` packages the review skill for Claude Code and Codex, which opencode
|
|
39
|
+
also discovers with no extra step.
|
|
36
40
|
- **Fast local review:** map definitions, callers, dependencies, routes,
|
|
37
41
|
inheritance, and affected tests without uploading or executing the project.
|
|
38
42
|
- **Open-source intelligence:** clone and analyse a GitHub repository with one
|
|
@@ -160,7 +164,7 @@ codingest skill install # code-review Agent Skill
|
|
|
160
164
|
```
|
|
161
165
|
|
|
162
166
|
The wheel bundles every grammar plus the `codingest` and `codingest-mcp`
|
|
163
|
-
commands. KGLite ≥0.15.
|
|
167
|
+
commands. KGLite ≥0.15.6 is installed automatically as the query/storage
|
|
164
168
|
engine; its MCP server and the transitive `mcp-methods` framework power the
|
|
165
169
|
builder-aware Codingest server. Nothing else needs to be installed.
|
|
166
170
|
|
|
@@ -173,7 +177,7 @@ Python prerequisites.
|
|
|
173
177
|
```toml
|
|
174
178
|
[dependencies]
|
|
175
179
|
codingest = "0.1"
|
|
176
|
-
kglite = "0.15.
|
|
180
|
+
kglite = "0.15.6"
|
|
177
181
|
```
|
|
178
182
|
|
|
179
183
|
```rust
|
|
@@ -245,7 +249,7 @@ diagnostic.
|
|
|
245
249
|
## Dependency policy
|
|
246
250
|
|
|
247
251
|
`kglite` and `kglite-mcp-server` use matching crates.io requirements with a
|
|
248
|
-
0.15.
|
|
252
|
+
0.15.6 minimum and a shared lockfile. This keeps the builder, persistence
|
|
249
253
|
handoff, and embedded MCP server on one compatible engine patch line.
|
|
250
254
|
|
|
251
255
|
## Parity with the (now-removed) in-tree component
|
|
@@ -10,7 +10,7 @@ keywords = ["knowledge-graph", "code-analysis", "tree-sitter", "cypher", "kglite
|
|
|
10
10
|
categories = ["development-tools", "parser-implementations"]
|
|
11
11
|
|
|
12
12
|
# Requires the kglite 0.15 engine API (`kglite::api::code_entities`); the
|
|
13
|
-
# workspace pins the current 0.15 patch floor (0.15.
|
|
13
|
+
# workspace pins the current 0.15 patch floor (0.15.6).
|
|
14
14
|
|
|
15
15
|
[lib]
|
|
16
16
|
name = "codingest"
|
|
@@ -486,6 +486,11 @@ fn main() {
|
|
|
486
486
|
"corpus_files": corpus.sha256.as_ref().map(|_| corpus.files),
|
|
487
487
|
"corpus_bytes": corpus.sha256.as_ref().map(|_| corpus.bytes),
|
|
488
488
|
"corpus_sha256": corpus.sha256,
|
|
489
|
+
// Fixed build configuration, echoed so a recorded row states it.
|
|
490
|
+
// Unlike codingest_stats, this harness has always built docs-ON,
|
|
491
|
+
// so the docs pass IS in its build times and node counts.
|
|
492
|
+
"include_tests": false,
|
|
493
|
+
"include_docs": true,
|
|
489
494
|
"nodes": nodes,
|
|
490
495
|
"edges": edges,
|
|
491
496
|
"build_a_secs": (build_a_secs * 1000.0).round() / 1000.0,
|
|
@@ -15,10 +15,21 @@
|
|
|
15
15
|
//! Usage:
|
|
16
16
|
//! cargo run -p codingest --bin codingest_stats --release -- <path>
|
|
17
17
|
//! cargo run -p codingest --bin codingest_stats --release -- <path> --include-tests
|
|
18
|
+
//! cargo run -p codingest --bin codingest_stats --release -- <path> --include-docs
|
|
18
19
|
//! cargo run -p codingest --bin codingest_stats --release -- <path> --function-metrics
|
|
19
20
|
//! cargo run -p codingest --bin codingest_stats --release -- <path> --edge-breakdown
|
|
20
21
|
//! cargo run -p codingest --bin codingest_stats --release -- <path> --dump-calls a,b,c
|
|
21
22
|
//!
|
|
23
|
+
//! `--include-docs` turns the docs pass on. It is **off by default**, which is
|
|
24
|
+
//! the configuration every historical row in `dev-docs/bench/results/` was
|
|
25
|
+
//! measured at, so the default is the comparable one; without the flag `:Doc`,
|
|
26
|
+
//! `:MENTIONS` and `:DOCUMENTS` are structurally absent and no docs-pass
|
|
27
|
+
//! regression — in node counts or in build time — can be seen here. Both the
|
|
28
|
+
//! tests and the docs configuration are echoed into the emitted JSON so a
|
|
29
|
+
//! recorded row states the configuration it was taken under, and an unknown
|
|
30
|
+
//! flag is a usage error rather than a silently-ignored typo that would report
|
|
31
|
+
//! a measurement under a mode it never ran in.
|
|
32
|
+
//!
|
|
22
33
|
//! `--edge-breakdown` appends a per-connection-type edge histogram to the JSON
|
|
23
34
|
//! object, with `IMPORTS` split by endpoint node type (`IMPORTS(File->File)`
|
|
24
35
|
//! vs `IMPORTS(File->Module)`) — the two are the same connection type but
|
|
@@ -231,37 +242,76 @@ fn dump_calls(graph: &DirGraph, names: &BTreeSet<String>) -> Vec<CallRow> {
|
|
|
231
242
|
rows
|
|
232
243
|
}
|
|
233
244
|
|
|
245
|
+
const USAGE: &str = "usage: codingest_stats <path> [--include-tests] [--include-docs] \
|
|
246
|
+
[--function-metrics] [--edge-breakdown] [--dump-calls name1,name2,...]";
|
|
247
|
+
|
|
248
|
+
/// Everything the command line can say, parsed once so the configuration a run
|
|
249
|
+
/// was taken under is a value that can be echoed and tested rather than a
|
|
250
|
+
/// scatter of `any(|a| a == …)` predicates.
|
|
251
|
+
#[derive(Debug, Default, PartialEq, Eq)]
|
|
252
|
+
struct Options {
|
|
253
|
+
include_tests: bool,
|
|
254
|
+
include_docs: bool,
|
|
255
|
+
function_metrics: bool,
|
|
256
|
+
edge_breakdown: bool,
|
|
257
|
+
dump_calls: Option<BTreeSet<String>>,
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/// Parse the arguments after `<path>`. Rejects anything unrecognised: a
|
|
261
|
+
/// typo'd `--include-dcos` must not report a docs-off measurement as a docs-on
|
|
262
|
+
/// one, which is the same reason `codingest_bench` rejects unknown flags.
|
|
263
|
+
fn parse_options(args: &[String]) -> Result<Options, String> {
|
|
264
|
+
let mut out = Options::default();
|
|
265
|
+
let mut i = 0;
|
|
266
|
+
while i < args.len() {
|
|
267
|
+
match args[i].as_str() {
|
|
268
|
+
"--include-tests" => out.include_tests = true,
|
|
269
|
+
"--include-docs" => out.include_docs = true,
|
|
270
|
+
"--function-metrics" => out.function_metrics = true,
|
|
271
|
+
"--edge-breakdown" => out.edge_breakdown = true,
|
|
272
|
+
"--dump-calls" => {
|
|
273
|
+
let list = args.get(i + 1).ok_or_else(|| {
|
|
274
|
+
"--dump-calls requires a comma-separated name list".to_string()
|
|
275
|
+
})?;
|
|
276
|
+
out.dump_calls = Some(
|
|
277
|
+
list.split(',')
|
|
278
|
+
.map(str::trim)
|
|
279
|
+
.filter(|s| !s.is_empty())
|
|
280
|
+
.map(str::to_string)
|
|
281
|
+
.collect(),
|
|
282
|
+
);
|
|
283
|
+
i += 1;
|
|
284
|
+
}
|
|
285
|
+
other => return Err(format!("unknown argument `{other}`")),
|
|
286
|
+
}
|
|
287
|
+
i += 1;
|
|
288
|
+
}
|
|
289
|
+
Ok(out)
|
|
290
|
+
}
|
|
291
|
+
|
|
234
292
|
fn main() {
|
|
235
293
|
let mut args = std::env::args().skip(1);
|
|
236
294
|
let path = match args.next() {
|
|
237
295
|
Some(p) => p,
|
|
238
296
|
None => {
|
|
239
|
-
eprintln!(
|
|
240
|
-
"usage: codingest_stats <path> [--include-tests] [--function-metrics] \
|
|
241
|
-
[--edge-breakdown] [--dump-calls name1,name2,...]"
|
|
242
|
-
);
|
|
297
|
+
eprintln!("{USAGE}");
|
|
243
298
|
std::process::exit(2);
|
|
244
299
|
}
|
|
245
300
|
};
|
|
246
|
-
let
|
|
247
|
-
let
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
None => {
|
|
261
|
-
eprintln!("--dump-calls requires a comma-separated name list");
|
|
262
|
-
std::process::exit(2);
|
|
263
|
-
}
|
|
264
|
-
});
|
|
301
|
+
let rest: Vec<String> = args.collect();
|
|
302
|
+
let options = match parse_options(&rest) {
|
|
303
|
+
Ok(options) => options,
|
|
304
|
+
Err(e) => {
|
|
305
|
+
eprintln!("{e}");
|
|
306
|
+
eprintln!("{USAGE}");
|
|
307
|
+
std::process::exit(2);
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
let include_tests = options.include_tests;
|
|
311
|
+
let include_docs = options.include_docs;
|
|
312
|
+
let emit_function_metrics = options.function_metrics;
|
|
313
|
+
let emit_edge_breakdown = options.edge_breakdown;
|
|
314
|
+
let dump_call_names = options.dump_calls.clone();
|
|
265
315
|
|
|
266
316
|
let t = Instant::now();
|
|
267
317
|
let (graph, stats) = match codingest::builder::run_with_options_stats(
|
|
@@ -270,7 +320,7 @@ fn main() {
|
|
|
270
320
|
include_tests,
|
|
271
321
|
None,
|
|
272
322
|
None,
|
|
273
|
-
|
|
323
|
+
include_docs,
|
|
274
324
|
) {
|
|
275
325
|
Ok(pair) => pair,
|
|
276
326
|
Err(e) => {
|
|
@@ -306,6 +356,7 @@ fn main() {
|
|
|
306
356
|
let mut out = serde_json::json!({
|
|
307
357
|
"path": path,
|
|
308
358
|
"include_tests": include_tests,
|
|
359
|
+
"include_docs": include_docs,
|
|
309
360
|
"build_secs": (build_secs * 1000.0).round() / 1000.0,
|
|
310
361
|
"nodes": graph.graph.node_count(),
|
|
311
362
|
"edges": graph.graph.edge_count(),
|
|
@@ -343,6 +394,97 @@ mod tests {
|
|
|
343
394
|
.expect("corpus build")
|
|
344
395
|
}
|
|
345
396
|
|
|
397
|
+
fn opts(args: &[&str]) -> Result<Options, String> {
|
|
398
|
+
parse_options(&args.iter().map(|a| a.to_string()).collect::<Vec<_>>())
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
#[test]
|
|
402
|
+
fn parse_options_defaults_to_the_historical_configuration() {
|
|
403
|
+
// Every row in dev-docs/bench/results/ predating --include-docs was
|
|
404
|
+
// measured tests-off/docs-off; the default must stay that way or old
|
|
405
|
+
// and new rows silently stop being comparable.
|
|
406
|
+
let parsed = opts(&[]).expect("empty argv parses");
|
|
407
|
+
assert_eq!(parsed, Options::default());
|
|
408
|
+
assert!(!parsed.include_tests);
|
|
409
|
+
assert!(!parsed.include_docs);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
#[test]
|
|
413
|
+
fn parse_options_reads_every_flag_including_docs() {
|
|
414
|
+
let parsed = opts(&[
|
|
415
|
+
"--include-tests",
|
|
416
|
+
"--include-docs",
|
|
417
|
+
"--edge-breakdown",
|
|
418
|
+
"--function-metrics",
|
|
419
|
+
"--dump-calls",
|
|
420
|
+
"run, helper ,,other",
|
|
421
|
+
])
|
|
422
|
+
.expect("all flags parse");
|
|
423
|
+
assert!(parsed.include_tests);
|
|
424
|
+
assert!(parsed.include_docs);
|
|
425
|
+
assert!(parsed.edge_breakdown);
|
|
426
|
+
assert!(parsed.function_metrics);
|
|
427
|
+
assert_eq!(
|
|
428
|
+
parsed.dump_calls,
|
|
429
|
+
Some(BTreeSet::from([
|
|
430
|
+
"run".to_string(),
|
|
431
|
+
"helper".to_string(),
|
|
432
|
+
"other".to_string()
|
|
433
|
+
])),
|
|
434
|
+
"the name list is split, trimmed and empties dropped"
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
#[test]
|
|
439
|
+
fn parse_options_rejects_an_unknown_flag_but_not_a_dump_calls_value() {
|
|
440
|
+
// A typo must be a usage error: silently ignoring it would report a
|
|
441
|
+
// measurement under a configuration the run never used.
|
|
442
|
+
assert_eq!(
|
|
443
|
+
opts(&["--include-dcos"]),
|
|
444
|
+
Err("unknown argument `--include-dcos`".to_string())
|
|
445
|
+
);
|
|
446
|
+
assert_eq!(
|
|
447
|
+
opts(&["--dump-calls"]),
|
|
448
|
+
Err("--dump-calls requires a comma-separated name list".to_string())
|
|
449
|
+
);
|
|
450
|
+
// The value that follows --dump-calls is consumed, not re-inspected as
|
|
451
|
+
// a flag — even when it looks like one.
|
|
452
|
+
let parsed = opts(&["--dump-calls", "--include-docs", "--include-tests"])
|
|
453
|
+
.expect("the value after --dump-calls is a value");
|
|
454
|
+
assert!(!parsed.include_docs, "the value was not read as a flag");
|
|
455
|
+
assert!(parsed.include_tests);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
#[test]
|
|
459
|
+
fn include_docs_is_what_makes_doc_nodes_visible() {
|
|
460
|
+
// The gap this flag closes: with the docs pass off — the hard-coded
|
|
461
|
+
// behaviour before it existed — a :Doc node cannot appear in any
|
|
462
|
+
// codingest_stats number, so no docs-pass regression can fail a gate.
|
|
463
|
+
fn doc_nodes(include_docs: bool) -> usize {
|
|
464
|
+
let graph = codingest::builder::run_with_options(
|
|
465
|
+
&corpus("docs_mdx"),
|
|
466
|
+
false,
|
|
467
|
+
true,
|
|
468
|
+
None,
|
|
469
|
+
None,
|
|
470
|
+
include_docs,
|
|
471
|
+
)
|
|
472
|
+
.expect("corpus build");
|
|
473
|
+
let params = HashMap::new();
|
|
474
|
+
let options = session::ExecuteOptions::eager(¶ms);
|
|
475
|
+
session::execute_read(&graph, "MATCH (d:Doc) RETURN d.name", &options)
|
|
476
|
+
.expect("query docs")
|
|
477
|
+
.result
|
|
478
|
+
.rows
|
|
479
|
+
.len()
|
|
480
|
+
}
|
|
481
|
+
assert_eq!(doc_nodes(false), 0, "docs off means no Doc node exists");
|
|
482
|
+
assert!(
|
|
483
|
+
doc_nodes(true) > 0,
|
|
484
|
+
"docs on must surface the docs_mdx corpus's Doc nodes"
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
|
|
346
488
|
#[test]
|
|
347
489
|
fn short_name_takes_the_rightmost_separator_of_any_flavour() {
|
|
348
490
|
assert_eq!(short_name("pkg.util.helper"), "helper");
|