cg-code-graph 0.10.1__py3-none-any.whl
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.
- cg_code_graph-0.10.1.dist-info/METADATA +678 -0
- cg_code_graph-0.10.1.dist-info/RECORD +174 -0
- cg_code_graph-0.10.1.dist-info/WHEEL +5 -0
- cg_code_graph-0.10.1.dist-info/entry_points.txt +3 -0
- cg_code_graph-0.10.1.dist-info/licenses/LICENSE +21 -0
- cg_code_graph-0.10.1.dist-info/top_level.txt +1 -0
- codegraph/__init__.py +2 -0
- codegraph/aitools.py +129 -0
- codegraph/apps.py +76 -0
- codegraph/blindspots.py +428 -0
- codegraph/bridges.py +1701 -0
- codegraph/cli.py +725 -0
- codegraph/concepts.py +362 -0
- codegraph/config.py +559 -0
- codegraph/core/__init__.py +0 -0
- codegraph/core/cache.py +375 -0
- codegraph/core/detect.py +80 -0
- codegraph/core/extractors.py +187 -0
- codegraph/core/fsutil.py +61 -0
- codegraph/core/generated.py +575 -0
- codegraph/core/model.py +174 -0
- codegraph/core/paths.py +175 -0
- codegraph/core/plugin.py +160 -0
- codegraph/core/store.py +80 -0
- codegraph/core/syntax_errors.py +132 -0
- codegraph/coverage.py +928 -0
- codegraph/doctor.py +453 -0
- codegraph/external.py +613 -0
- codegraph/indexer.py +336 -0
- codegraph/link.py +434 -0
- codegraph/lint_async.py +524 -0
- codegraph/mcp_server.py +1303 -0
- codegraph/parity.py +473 -0
- codegraph/parity_structure.py +307 -0
- codegraph/payload.py +321 -0
- codegraph/plans.py +1285 -0
- codegraph/platform_scan.py +643 -0
- codegraph/platforms.py +1369 -0
- codegraph/plugins/__init__.py +0 -0
- codegraph/plugins/cfamily/__init__.py +0 -0
- codegraph/plugins/cfamily/plugin.py +930 -0
- codegraph/plugins/cfamily/syntax.py +881 -0
- codegraph/plugins/dart/__init__.py +0 -0
- codegraph/plugins/dart/bridges.py +345 -0
- codegraph/plugins/dart/extractor/bin/extract.dart +717 -0
- codegraph/plugins/dart/extractor/pubspec.lock +149 -0
- codegraph/plugins/dart/extractor/pubspec.yaml +7 -0
- codegraph/plugins/dart/http.py +904 -0
- codegraph/plugins/dart/models.py +308 -0
- codegraph/plugins/dart/plugin.py +625 -0
- codegraph/plugins/dart/program.py +907 -0
- codegraph/plugins/django/__init__.py +0 -0
- codegraph/plugins/django/extras.py +378 -0
- codegraph/plugins/django/models.py +508 -0
- codegraph/plugins/django/plugin.py +728 -0
- codegraph/plugins/django/schemas.py +339 -0
- codegraph/plugins/django/shapes.py +216 -0
- codegraph/plugins/django/urls.py +603 -0
- codegraph/plugins/express/__init__.py +0 -0
- codegraph/plugins/express/plugin.py +428 -0
- codegraph/plugins/flutter/__init__.py +0 -0
- codegraph/plugins/flutter/plugin.py +538 -0
- codegraph/plugins/kotlin/__init__.py +0 -0
- codegraph/plugins/kotlin/exact.py +457 -0
- codegraph/plugins/kotlin/plugin.py +1961 -0
- codegraph/plugins/kotlin/reparse.py +234 -0
- codegraph/plugins/laravel/__init__.py +0 -0
- codegraph/plugins/laravel/broadcast.py +351 -0
- codegraph/plugins/laravel/plugin.py +863 -0
- codegraph/plugins/laravel/tests.py +262 -0
- codegraph/plugins/laravel/values.py +728 -0
- codegraph/plugins/native/__init__.py +0 -0
- codegraph/plugins/native/gates.py +286 -0
- codegraph/plugins/native/runner.py +183 -0
- codegraph/plugins/native/scipread.py +194 -0
- codegraph/plugins/native/ts.py +54 -0
- codegraph/plugins/nest/__init__.py +0 -0
- codegraph/plugins/nest/plugin.py +654 -0
- codegraph/plugins/nextjs/__init__.py +0 -0
- codegraph/plugins/nextjs/plugin.py +336 -0
- codegraph/plugins/nuxt/__init__.py +0 -0
- codegraph/plugins/nuxt/plugin.py +308 -0
- codegraph/plugins/php/__init__.py +0 -0
- codegraph/plugins/php/extractor/composer.json +5 -0
- codegraph/plugins/php/extractor/composer.lock +76 -0
- codegraph/plugins/php/extractor/extract.php +743 -0
- codegraph/plugins/php/gating.py +573 -0
- codegraph/plugins/php/plugin.py +668 -0
- codegraph/plugins/php/strings.py +197 -0
- codegraph/plugins/python/__init__.py +0 -0
- codegraph/plugins/python/aitools.py +664 -0
- codegraph/plugins/python/external.py +245 -0
- codegraph/plugins/python/fields.py +107 -0
- codegraph/plugins/python/plugin.py +1733 -0
- codegraph/plugins/python/refs.py +485 -0
- codegraph/plugins/python/roots.py +412 -0
- codegraph/plugins/python/socketio.py +210 -0
- codegraph/plugins/python/subproc.py +864 -0
- codegraph/plugins/python/tests.py +1040 -0
- codegraph/plugins/python/values.py +179 -0
- codegraph/plugins/pyweb/__init__.py +0 -0
- codegraph/plugins/pyweb/plugin.py +1334 -0
- codegraph/plugins/pyweb/values.py +68 -0
- codegraph/plugins/rust/__init__.py +0 -0
- codegraph/plugins/rust/cargo.py +226 -0
- codegraph/plugins/rust/plugin.py +980 -0
- codegraph/plugins/rust/syntax.py +678 -0
- codegraph/plugins/scip/__init__.py +0 -0
- codegraph/plugins/scip/importer.py +129 -0
- codegraph/plugins/scip/scip.proto +962 -0
- codegraph/plugins/scip/scip_pb2.py +97 -0
- codegraph/plugins/stubs/__init__.py +0 -0
- codegraph/plugins/stubs/plugins.py +38 -0
- codegraph/plugins/swift/__init__.py +0 -0
- codegraph/plugins/swift/baseurl.py +109 -0
- codegraph/plugins/swift/exact.py +415 -0
- codegraph/plugins/swift/indexstore.py +209 -0
- codegraph/plugins/swift/packages.py +174 -0
- codegraph/plugins/swift/plugin.py +2890 -0
- codegraph/plugins/ts/__init__.py +0 -0
- codegraph/plugins/ts/baseurl.py +185 -0
- codegraph/plugins/ts/extractor/extract.mjs +2652 -0
- codegraph/plugins/ts/extractor/fw.mjs +685 -0
- codegraph/plugins/ts/extractor/package-lock.json +205 -0
- codegraph/plugins/ts/extractor/package.json +9 -0
- codegraph/plugins/ts/plugin.py +480 -0
- codegraph/plugins/tsweb/__init__.py +0 -0
- codegraph/plugins/tsweb/common.py +290 -0
- codegraph/plugins/tsweb/data.py +276 -0
- codegraph/presets/__init__.py +146 -0
- codegraph/presets/c_cpp.yaml +9 -0
- codegraph/presets/common.yaml +66 -0
- codegraph/presets/dart.yaml +9 -0
- codegraph/presets/django-ninja.yaml +15 -0
- codegraph/presets/django.yaml +25 -0
- codegraph/presets/djangorestframework.yaml +17 -0
- codegraph/presets/express.yaml +17 -0
- codegraph/presets/kotlin.yaml +11 -0
- codegraph/presets/laravel.yaml +40 -0
- codegraph/presets/nest.yaml +11 -0
- codegraph/presets/nextjs.yaml +15 -0
- codegraph/presets/nuxt.yaml +9 -0
- codegraph/presets/php.yaml +5 -0
- codegraph/presets/python.yaml +10 -0
- codegraph/presets/rust.yaml +5 -0
- codegraph/presets/swift.yaml +10 -0
- codegraph/presets/typescript.yaml +13 -0
- codegraph/process_runs.py +328 -0
- codegraph/protocols/__init__.py +299 -0
- codegraph/protocols/builtin.py +67 -0
- codegraph/protocols/matchers.py +144 -0
- codegraph/protocols/view.py +334 -0
- codegraph/query.py +2089 -0
- codegraph/realtime.py +260 -0
- codegraph/roundtrip.py +346 -0
- codegraph/routes.py +442 -0
- codegraph/starters.py +218 -0
- codegraph/tests_index.py +117 -0
- codegraph/viz/__init__.py +0 -0
- codegraph/viz/graph.py +369 -0
- codegraph/viz/server.py +198 -0
- codegraph/viz/static/app.css +148 -0
- codegraph/viz/static/app.js +1082 -0
- codegraph/viz/static/index.html +81 -0
- codegraph/viz/static/layered.js +237 -0
- codegraph/viz/static/vendor/VERSIONS.txt +4 -0
- codegraph/viz/static/vendor/cose-base.js +3214 -0
- codegraph/viz/static/vendor/cytoscape-fcose.js +1549 -0
- codegraph/viz/static/vendor/cytoscape.min.js +31 -0
- codegraph/viz/static/vendor/layout-base.js +5230 -0
- codegraph/viz/tools/package-lock.json +303 -0
- codegraph/viz/tools/package.json +7 -0
- codegraph/viz/tools/shoot.mjs +165 -0
- codegraph/xcode.py +251 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""String values of Python expressions, evaluated statically (no code runs): literals, f-strings, `+` / `%` /
|
|
2
|
+
`.format`, module and imported constants, class attribute defaults read through an instance (`settings.API_V1_STR`
|
|
3
|
+
with `settings = Settings()` and `API_V1_STR: str = "/api/v1"`). Used for route prefixes / paths and test URLs."""
|
|
4
|
+
from __future__ import annotations
|
|
5
|
+
|
|
6
|
+
import ast
|
|
7
|
+
|
|
8
|
+
UNKNOWN = "{?}"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def str_value(prog, e, ctx, depth: int = 0) -> str | None:
|
|
12
|
+
"""The string value of `e`, or None when it cannot be determined. f-string parts that cannot be evaluated
|
|
13
|
+
become `{name}` placeholders (a path parameter in a URL)."""
|
|
14
|
+
from ..python.plugin import Ctx
|
|
15
|
+
if e is None or depth > 8:
|
|
16
|
+
return None
|
|
17
|
+
if isinstance(e, ast.Constant):
|
|
18
|
+
return e.value if isinstance(e.value, str) else None
|
|
19
|
+
if isinstance(e, ast.JoinedStr):
|
|
20
|
+
out = ""
|
|
21
|
+
for v in e.values:
|
|
22
|
+
if isinstance(v, ast.Constant):
|
|
23
|
+
out += str(v.value)
|
|
24
|
+
continue
|
|
25
|
+
s = str_value(prog, v.value, ctx, depth + 1)
|
|
26
|
+
out += s if s is not None else "{" + _ph(v.value) + "}"
|
|
27
|
+
return out
|
|
28
|
+
if isinstance(e, ast.BinOp) and isinstance(e.op, ast.Add):
|
|
29
|
+
a, b = str_value(prog, e.left, ctx, depth + 1), str_value(prog, e.right, ctx, depth + 1)
|
|
30
|
+
return a + b if a is not None and b is not None else None
|
|
31
|
+
if isinstance(e, ast.Name):
|
|
32
|
+
if ctx.func is not None:
|
|
33
|
+
lv = prog.local_vars(ctx).get(e.id)
|
|
34
|
+
if lv is not None:
|
|
35
|
+
vals = [v for v, _a, kind in lv if kind == "assign" and v is not None]
|
|
36
|
+
return str_value(prog, vals[0], ctx, depth + 1) if len(vals) == 1 else None
|
|
37
|
+
r = prog.resolve_name(ctx.mod, e.id)
|
|
38
|
+
if r and r[0] == "var":
|
|
39
|
+
vals = [v for v, _ln, _ann in r[1].vars.get(r[2], ()) if v is not None]
|
|
40
|
+
return str_value(prog, vals[0], Ctx(r[1], None, None), depth + 1) if len(vals) == 1 else None
|
|
41
|
+
return None
|
|
42
|
+
if isinstance(e, ast.Attribute):
|
|
43
|
+
try:
|
|
44
|
+
t = prog.infer(e.value, ctx)
|
|
45
|
+
except RecursionError:
|
|
46
|
+
return None
|
|
47
|
+
if t and t[0] == "var":
|
|
48
|
+
t = prog.var_type(t[1], t[2]) if hasattr(prog, "var_type") else None
|
|
49
|
+
if t and t[0] == "mod":
|
|
50
|
+
m = t[1]
|
|
51
|
+
vals = [v for v, _ln, _ann in m.vars.get(e.attr, ()) if v is not None]
|
|
52
|
+
return str_value(prog, vals[0], Ctx(m, None, None), depth + 1) if len(vals) == 1 else None
|
|
53
|
+
if t and t[0] in ("inst", "type"):
|
|
54
|
+
c = t[1]
|
|
55
|
+
for k in [c] + [b[1] for b in prog.mro(c) if b[0] == "type"]:
|
|
56
|
+
if e.attr in k.attrs:
|
|
57
|
+
val = k.attrs[e.attr][0]
|
|
58
|
+
return str_value(prog, val, Ctx(k.module, None, k), depth + 1) if val is not None else None
|
|
59
|
+
return None
|
|
60
|
+
return None
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def _ph(e) -> str:
|
|
64
|
+
if isinstance(e, ast.Name):
|
|
65
|
+
return e.id
|
|
66
|
+
if isinstance(e, ast.Attribute):
|
|
67
|
+
return e.attr
|
|
68
|
+
return "p"
|
|
File without changes
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"""Cargo workspace discovery: packages, targets, features (no build, no code execution).
|
|
2
|
+
|
|
3
|
+
Uses `cargo metadata --no-deps --offline` when cargo is installed (handles workspace inheritance, globs,
|
|
4
|
+
auto-discovered targets); falls back to reading Cargo.toml files with tomllib and Cargo's auto-discovery rules.
|
|
5
|
+
"""
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import glob
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
import shutil
|
|
12
|
+
import subprocess
|
|
13
|
+
import tomllib
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
|
|
17
|
+
LIB_KINDS = {"lib", "rlib", "dylib", "cdylib", "staticlib", "proc-macro"}
|
|
18
|
+
from ... import presets
|
|
19
|
+
|
|
20
|
+
# Cargo build output, vendored sources, Cargo home (codegraph/presets/rust.yaml; .cg.yaml skip_dirs adjusts them)
|
|
21
|
+
SKIP_DIRS = presets.skip_dirs("rust")
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
@dataclass
|
|
25
|
+
class Target:
|
|
26
|
+
kind: str # lib | bin | test | bench | example | build
|
|
27
|
+
name: str
|
|
28
|
+
src: str # repo-relative path of the crate root file
|
|
29
|
+
crate: str # crate path used in node ids, e.g. kv_core, kv, kv_core[test:roundtrip]
|
|
30
|
+
crate_types: list = field(default_factory=list)
|
|
31
|
+
required_features: list = field(default_factory=list)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
@dataclass
|
|
35
|
+
class Package:
|
|
36
|
+
name: str
|
|
37
|
+
dir: str # repo-relative directory ('' = root)
|
|
38
|
+
manifest: str
|
|
39
|
+
version: str = ""
|
|
40
|
+
features: dict = field(default_factory=dict)
|
|
41
|
+
targets: list = field(default_factory=list)
|
|
42
|
+
deps: list = field(default_factory=list) # dependency package names (workspace-internal ones are linked)
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def crate_name(self) -> str:
|
|
46
|
+
return self.name.replace("-", "_")
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _norm(s: str) -> str:
|
|
50
|
+
return s.replace("-", "_")
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _rel(root: Path, p: str | Path) -> str:
|
|
54
|
+
try:
|
|
55
|
+
return Path(p).resolve().relative_to(root).as_posix()
|
|
56
|
+
except ValueError:
|
|
57
|
+
return Path(p).as_posix()
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _crate_for(pkg: Package, kind: str, name: str, lib_names: set) -> str:
|
|
61
|
+
pc = pkg.crate_name
|
|
62
|
+
if kind == "lib":
|
|
63
|
+
return _norm(name)
|
|
64
|
+
if kind == "bin":
|
|
65
|
+
n = _norm(name)
|
|
66
|
+
return f"{n}[bin]" if n in lib_names else n
|
|
67
|
+
if kind == "build":
|
|
68
|
+
return f"{pc}[build]"
|
|
69
|
+
return f"{pc}[{kind}:{name}]"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def _kind_of(kinds: list[str]) -> str:
|
|
73
|
+
k = kinds[0] if kinds else "lib"
|
|
74
|
+
if k in LIB_KINDS or any(x in LIB_KINDS for x in kinds):
|
|
75
|
+
return "lib"
|
|
76
|
+
return {"custom-build": "build"}.get(k, k)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def from_metadata(root: Path) -> list[Package] | None:
|
|
80
|
+
cargo = os.environ.get("CODEGRAPH_CARGO") or shutil.which("cargo") or str(Path.home() / ".cargo/bin/cargo")
|
|
81
|
+
if not Path(cargo).exists() and not shutil.which(cargo):
|
|
82
|
+
return None
|
|
83
|
+
try:
|
|
84
|
+
r = subprocess.run([cargo, "metadata", "--no-deps", "--format-version", "1", "--offline"], cwd=root,
|
|
85
|
+
capture_output=True, text=True, timeout=180)
|
|
86
|
+
except (OSError, subprocess.TimeoutExpired):
|
|
87
|
+
return None
|
|
88
|
+
if r.returncode != 0:
|
|
89
|
+
return None
|
|
90
|
+
md = json.loads(r.stdout)
|
|
91
|
+
members = set(md.get("workspace_members") or [])
|
|
92
|
+
pkgs = []
|
|
93
|
+
for p in md["packages"]:
|
|
94
|
+
if members and p["id"] not in members:
|
|
95
|
+
continue
|
|
96
|
+
pdir = Path(p["manifest_path"]).parent
|
|
97
|
+
pkg = Package(p["name"], _rel(root, pdir) if pdir != root else "", _rel(root, p["manifest_path"]), p.get("version", ""),
|
|
98
|
+
{k: list(v) for k, v in (p.get("features") or {}).items()},
|
|
99
|
+
deps=[d["name"] for d in p.get("dependencies") or []])
|
|
100
|
+
lib_names = {_norm(t["name"]) for t in p["targets"] if _kind_of(t["kind"]) == "lib"}
|
|
101
|
+
for t in p["targets"]:
|
|
102
|
+
k = _kind_of(t["kind"])
|
|
103
|
+
pkg.targets.append(Target(k, t["name"], _rel(root, t["src_path"]), _crate_for(pkg, k, t["name"], lib_names),
|
|
104
|
+
list(t.get("crate_types") or []), list(t.get("required-features") or [])))
|
|
105
|
+
pkgs.append(pkg)
|
|
106
|
+
return pkgs
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def _members(root: Path, ws: dict) -> list[Path]:
|
|
110
|
+
out = []
|
|
111
|
+
excl = {(root / e).resolve() for e in ws.get("exclude", [])}
|
|
112
|
+
for m in ws.get("members", []):
|
|
113
|
+
for d in sorted(glob.glob(str(root / m))):
|
|
114
|
+
dp = Path(d).resolve()
|
|
115
|
+
if (dp / "Cargo.toml").exists() and dp not in excl:
|
|
116
|
+
out.append(dp)
|
|
117
|
+
return out
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def _inherit(v, ws_pkg: dict, key: str):
|
|
121
|
+
if isinstance(v, dict) and v.get("workspace"):
|
|
122
|
+
return ws_pkg.get(key)
|
|
123
|
+
return v
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def from_toml(root: Path) -> list[Package]:
|
|
127
|
+
"""Fallback without cargo: Cargo.toml + auto-discovery (src/lib.rs, src/main.rs, src/bin/*, tests/, benches/,
|
|
128
|
+
examples/, build.rs)."""
|
|
129
|
+
try:
|
|
130
|
+
top = tomllib.loads((root / "Cargo.toml").read_text())
|
|
131
|
+
except Exception:
|
|
132
|
+
return []
|
|
133
|
+
ws = top.get("workspace") or {}
|
|
134
|
+
ws_pkg = ws.get("package") or {}
|
|
135
|
+
dirs = []
|
|
136
|
+
if "package" in top:
|
|
137
|
+
dirs.append(root)
|
|
138
|
+
dirs += [d for d in _members(root, ws) if d != root]
|
|
139
|
+
return _packages(root, dirs, ws_pkg)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def tauri_crates(root: Path, depth: int = 4) -> list[Path]:
|
|
143
|
+
"""Without a root Cargo.toml: the Rust core of Tauri apps, <app>/src-tauri/Cargo.toml (a JS project root)."""
|
|
144
|
+
out = []
|
|
145
|
+
for dp, dn, fn in os.walk(root):
|
|
146
|
+
d = Path(dp)
|
|
147
|
+
rel = d.relative_to(root)
|
|
148
|
+
dn[:] = sorted(x for x in dn if not x.startswith(".") and x not in ("node_modules", "target", "dist", "build"))
|
|
149
|
+
if d.name == "src-tauri" and "Cargo.toml" in fn:
|
|
150
|
+
out.append(d)
|
|
151
|
+
dn[:] = []
|
|
152
|
+
if len(rel.parts) >= depth:
|
|
153
|
+
dn[:] = []
|
|
154
|
+
return out
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _packages(root: Path, dirs: list[Path], ws_pkg: dict) -> list[Package]:
|
|
158
|
+
pkgs = []
|
|
159
|
+
for d in dirs:
|
|
160
|
+
try:
|
|
161
|
+
t = tomllib.loads((d / "Cargo.toml").read_text())
|
|
162
|
+
except Exception:
|
|
163
|
+
continue
|
|
164
|
+
p = t.get("package") or {}
|
|
165
|
+
name = p.get("name") or d.name
|
|
166
|
+
pkg = Package(name, _rel(root, d) if d != root else "", _rel(root, d / "Cargo.toml"),
|
|
167
|
+
str(_inherit(p.get("version", ""), ws_pkg, "version") or ""),
|
|
168
|
+
{k: list(v) for k, v in (t.get("features") or {}).items()},
|
|
169
|
+
deps=list((t.get("dependencies") or {}).keys()))
|
|
170
|
+
tl = []
|
|
171
|
+
lib = t.get("lib") or {}
|
|
172
|
+
lib_path = lib.get("path") or ("src/lib.rs" if (d / "src/lib.rs").exists() else None)
|
|
173
|
+
if lib_path:
|
|
174
|
+
tl.append(("lib", lib.get("name") or _norm(name), lib_path, lib.get("crate-type") or ["lib"], []))
|
|
175
|
+
seen_bins = set()
|
|
176
|
+
for b in t.get("bin") or []:
|
|
177
|
+
path = b.get("path") or (f"src/bin/{b['name']}.rs" if (d / f"src/bin/{b['name']}.rs").exists() else
|
|
178
|
+
f"src/bin/{b['name']}/main.rs" if (d / f"src/bin/{b['name']}/main.rs").exists() else "src/main.rs")
|
|
179
|
+
tl.append(("bin", b["name"], path, ["bin"], b.get("required-features") or []))
|
|
180
|
+
seen_bins.add(path)
|
|
181
|
+
if p.get("autobins", True):
|
|
182
|
+
if (d / "src/main.rs").exists() and "src/main.rs" not in seen_bins:
|
|
183
|
+
tl.append(("bin", name, "src/main.rs", ["bin"], []))
|
|
184
|
+
for f in sorted((d / "src/bin").glob("*.rs")) if (d / "src/bin").is_dir() else []:
|
|
185
|
+
if f"src/bin/{f.name}" not in seen_bins:
|
|
186
|
+
tl.append(("bin", f.stem, f"src/bin/{f.name}", ["bin"], []))
|
|
187
|
+
for f in sorted((d / "src/bin").glob("*/main.rs")) if (d / "src/bin").is_dir() else []:
|
|
188
|
+
rp = f.relative_to(d).as_posix()
|
|
189
|
+
if rp not in seen_bins:
|
|
190
|
+
tl.append(("bin", f.parent.name, rp, ["bin"], []))
|
|
191
|
+
for kind, sect, auto in (("test", "test", "tests"), ("bench", "bench", "benches"), ("example", "example", "examples")):
|
|
192
|
+
listed = set()
|
|
193
|
+
for x in t.get(sect) or []:
|
|
194
|
+
path = x.get("path") or f"{auto}/{x['name']}.rs"
|
|
195
|
+
tl.append((kind, x["name"], path, ["bin"], x.get("required-features") or []))
|
|
196
|
+
listed.add(path)
|
|
197
|
+
if p.get(f"auto{auto}", True) and (d / auto).is_dir():
|
|
198
|
+
for f in sorted((d / auto).glob("*.rs")):
|
|
199
|
+
if f"{auto}/{f.name}" not in listed:
|
|
200
|
+
tl.append((kind, f.stem, f"{auto}/{f.name}", ["bin"], []))
|
|
201
|
+
for f in sorted((d / auto).glob("*/main.rs")):
|
|
202
|
+
rp = f.relative_to(d).as_posix()
|
|
203
|
+
if rp not in listed:
|
|
204
|
+
tl.append((kind, f.parent.name, rp, ["bin"], []))
|
|
205
|
+
build = p.get("build")
|
|
206
|
+
if build is None and (d / "build.rs").exists():
|
|
207
|
+
build = "build.rs"
|
|
208
|
+
if isinstance(build, str):
|
|
209
|
+
tl.append(("build", "build-script-build", build, ["bin"], []))
|
|
210
|
+
lib_names = {_norm(n) for k, n, *_ in tl if k == "lib"}
|
|
211
|
+
for kind, tname, path, ctypes, req in tl:
|
|
212
|
+
pkg.targets.append(Target(kind, tname, _rel(root, d / path), _crate_for(pkg, kind, tname, lib_names), ctypes, req))
|
|
213
|
+
pkgs.append(pkg)
|
|
214
|
+
return pkgs
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def discover(root: Path) -> tuple[list[Package], str]:
|
|
218
|
+
if not (root / "Cargo.toml").exists():
|
|
219
|
+
tc = tauri_crates(root)
|
|
220
|
+
if tc:
|
|
221
|
+
return _packages(root, tc, {}), "src-tauri/Cargo.toml"
|
|
222
|
+
if os.environ.get("CODEGRAPH_NO_CARGO") != "1":
|
|
223
|
+
md = from_metadata(root)
|
|
224
|
+
if md is not None:
|
|
225
|
+
return md, "cargo metadata"
|
|
226
|
+
return from_toml(root), "Cargo.toml (fallback)"
|