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,174 @@
|
|
|
1
|
+
"""SwiftPM modules (#90): the targets of every local `Package.swift`, the folder each one compiles and the targets
|
|
2
|
+
it depends on (its own `dependencies:`, `.product(name:package:)` of local packages, transitively). A file in a
|
|
3
|
+
package target sees only its own module and those dependencies, never app, extension, preview or test code; a file
|
|
4
|
+
outside every package target (an Xcode app, extension or preview folder) sees everything it links."""
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import re
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
|
|
10
|
+
TARGET = re.compile(r"\.(target|executableTarget|testTarget|macro|plugin|systemLibrary|binaryTarget)\s*\(\s*name\s*:\s*\"([^\"]+)\"")
|
|
11
|
+
PRODUCT = re.compile(r"\.(?:library|executable|plugin)\s*\(\s*name\s*:\s*\"([^\"]+)\"[^)]*?targets\s*:\s*\[([^\]]*)\]", re.S)
|
|
12
|
+
DEP_PRODUCT = re.compile(r"\.product\s*\(\s*name\s*:\s*\"([^\"]+)\"")
|
|
13
|
+
DEP_NAMED = re.compile(r"\.(?:target|byName)\s*\(\s*name\s*:\s*\"([^\"]+)\"")
|
|
14
|
+
DEP_STRING = re.compile(r"(?<![:\w])\s*\"([^\"]+)\"")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _call_body(txt: str, start: int) -> tuple[str, int]:
|
|
18
|
+
"""The text of the parenthesised call opening at or after `start`, up to its closing parenthesis (parentheses
|
|
19
|
+
inside string literals do not count), and the offset of that parenthesis."""
|
|
20
|
+
i = txt.find("(", start)
|
|
21
|
+
depth, j = 0, i
|
|
22
|
+
while 0 <= j < len(txt):
|
|
23
|
+
c = txt[j]
|
|
24
|
+
if c == "(":
|
|
25
|
+
depth += 1
|
|
26
|
+
elif c == ")":
|
|
27
|
+
depth -= 1
|
|
28
|
+
if depth == 0:
|
|
29
|
+
return txt[i + 1:j], j
|
|
30
|
+
elif c == '"':
|
|
31
|
+
k = txt.find('"', j + 1)
|
|
32
|
+
if k < 0:
|
|
33
|
+
break
|
|
34
|
+
j = k
|
|
35
|
+
j += 1
|
|
36
|
+
return txt[i + 1:], len(txt)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _array(body: str, key: str) -> str | None:
|
|
40
|
+
m = re.search(rf"\b{key}\s*:\s*\[", body)
|
|
41
|
+
if not m:
|
|
42
|
+
return None
|
|
43
|
+
depth, i = 0, m.end() - 1
|
|
44
|
+
for j in range(i, len(body)):
|
|
45
|
+
if body[j] == "[":
|
|
46
|
+
depth += 1
|
|
47
|
+
elif body[j] == "]":
|
|
48
|
+
depth -= 1
|
|
49
|
+
if depth == 0:
|
|
50
|
+
return body[i + 1:j]
|
|
51
|
+
return body[i + 1:]
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class SwiftPM:
|
|
55
|
+
def __init__(self, root: Path, files: list[str] | None = None):
|
|
56
|
+
"""`files`: the project's Swift files as the index walks them (skip presets applied); the manifests are the
|
|
57
|
+
`Package.swift` among them (default: the root and up to three folders down)."""
|
|
58
|
+
self.root = root
|
|
59
|
+
self._files = files
|
|
60
|
+
self.targets: dict[str, dict] = {} # "<package dir>:<name>" -> {name, path, deps (raw), kind}
|
|
61
|
+
self.products: dict[str, set[str]] = {} # product name -> target keys
|
|
62
|
+
self.manifests: list[str] = []
|
|
63
|
+
for pk in sorted(self._manifests()):
|
|
64
|
+
self._parse(pk)
|
|
65
|
+
by_name: dict[str, list[str]] = {}
|
|
66
|
+
for k, t in self.targets.items():
|
|
67
|
+
by_name.setdefault(t["name"], []).append(k)
|
|
68
|
+
self.visible: dict[str, set[str]] = {}
|
|
69
|
+
direct = {}
|
|
70
|
+
for k, t in self.targets.items():
|
|
71
|
+
pkg = k.rsplit(":", 1)[0]
|
|
72
|
+
out = set()
|
|
73
|
+
for kind, name in t["deps"]:
|
|
74
|
+
same = f"{pkg}:{name}"
|
|
75
|
+
if kind != "product" and same in self.targets:
|
|
76
|
+
out.add(same)
|
|
77
|
+
elif name in self.products:
|
|
78
|
+
out |= self.products[name]
|
|
79
|
+
elif kind != "product":
|
|
80
|
+
out |= set(by_name.get(name, ()))
|
|
81
|
+
direct[k] = out
|
|
82
|
+
for k in self.targets:
|
|
83
|
+
seen, todo = {k}, [k]
|
|
84
|
+
while todo:
|
|
85
|
+
for d in direct.get(todo.pop(), ()):
|
|
86
|
+
if d not in seen:
|
|
87
|
+
seen.add(d)
|
|
88
|
+
todo.append(d)
|
|
89
|
+
self.visible[k] = seen
|
|
90
|
+
every = set(self.targets)
|
|
91
|
+
for k, t in self.targets.items():
|
|
92
|
+
if t.get("deps_unknown"):
|
|
93
|
+
self.visible[k] = every
|
|
94
|
+
# longest target folder first
|
|
95
|
+
self._paths = sorted(((t["path"], k) for k, t in self.targets.items() if t["path"] is not None),
|
|
96
|
+
key=lambda x: -len(x[0]))
|
|
97
|
+
self._cache: dict[str, str | None] = {}
|
|
98
|
+
|
|
99
|
+
def _manifests(self):
|
|
100
|
+
if self._files is not None:
|
|
101
|
+
return [self.root / f for f in self._files if f.rsplit("/", 1)[-1] == "Package.swift" and f.count("/") <= 3]
|
|
102
|
+
out = []
|
|
103
|
+
for depth in range(0, 4):
|
|
104
|
+
for p in self.root.glob("/".join(["*"] * depth + ["Package.swift"])):
|
|
105
|
+
# (the index passes its file list, skip presets applied; this walk is for direct use)
|
|
106
|
+
if not any(x.startswith(".") for x in p.relative_to(self.root).parts[:-1]):
|
|
107
|
+
out.append(p)
|
|
108
|
+
return out
|
|
109
|
+
|
|
110
|
+
def _parse(self, pk: Path):
|
|
111
|
+
try:
|
|
112
|
+
txt = pk.read_text(encoding="utf-8", errors="replace")
|
|
113
|
+
except OSError:
|
|
114
|
+
return
|
|
115
|
+
txt = re.sub(r"//[^\n]*|/\*.*?\*/", " ", txt, flags=re.S)
|
|
116
|
+
d = pk.parent.relative_to(self.root).as_posix()
|
|
117
|
+
d = "" if d == "." else d
|
|
118
|
+
self.manifests.append(pk.relative_to(self.root).as_posix())
|
|
119
|
+
end = -1
|
|
120
|
+
for m in TARGET.finditer(txt):
|
|
121
|
+
if m.start() < end:
|
|
122
|
+
continue # `.target(name: "Csqlite3")` in another target's `dependencies:`
|
|
123
|
+
kind, name = m.groups()
|
|
124
|
+
body, end = _call_body(txt, m.start())
|
|
125
|
+
deps = []
|
|
126
|
+
arr = _array(body, "dependencies")
|
|
127
|
+
# dependencies the manifest computes (`dependencies: shared`, `[...] + extra`): unknown, so the target
|
|
128
|
+
# may name any package target (never app code)
|
|
129
|
+
unknown = bool(re.search(r"\bdependencies\s*:", body)) and (arr is None or bool(re.sub(
|
|
130
|
+
r"\.\w+\s*\((?:[^()]|\((?:[^()]|\([^()]*\))*\))*\)|\"[^\"]*\"|[\s,]", "", arr)) or bool(re.search(
|
|
131
|
+
r"\bdependencies\s*:\s*\[" + re.escape(arr) + r"\]\s*\+", body)))
|
|
132
|
+
if arr:
|
|
133
|
+
for x in DEP_PRODUCT.finditer(arr):
|
|
134
|
+
deps.append(("product", x.group(1)))
|
|
135
|
+
for x in DEP_NAMED.finditer(arr):
|
|
136
|
+
deps.append(("target", x.group(1)))
|
|
137
|
+
plain = re.sub(r"\.\w+\s*\((?:[^()]|\([^()]*\))*\)", " ", arr) # drop .product(...) / .target(...)
|
|
138
|
+
for x in DEP_STRING.finditer(plain):
|
|
139
|
+
deps.append(("name", x.group(1)))
|
|
140
|
+
pm = re.search(r"\bpath\s*:\s*\"([^\"]*)\"", body)
|
|
141
|
+
if kind in ("binaryTarget", "plugin") and not pm:
|
|
142
|
+
path = None
|
|
143
|
+
else:
|
|
144
|
+
sub = pm.group(1) if pm else (f"Tests/{name}" if kind == "testTarget" else
|
|
145
|
+
f"Plugins/{name}" if kind == "plugin" else f"Sources/{name}")
|
|
146
|
+
path = "/".join(x for x in (d, sub.strip("/")) if x)
|
|
147
|
+
self.targets[f"{d}:{name}"] = {"name": name, "path": path, "deps": deps, "kind": kind,
|
|
148
|
+
"deps_unknown": unknown}
|
|
149
|
+
for m in PRODUCT.finditer(txt):
|
|
150
|
+
names = re.findall(r"\"([^\"]+)\"", m.group(2))
|
|
151
|
+
self.products.setdefault(m.group(1), set()).update(f"{d}:{n}" for n in names)
|
|
152
|
+
|
|
153
|
+
def module_of(self, rel: str) -> str | None:
|
|
154
|
+
"""The package target compiling the file, or None (app / extension / preview code, or no package)."""
|
|
155
|
+
if rel in self._cache:
|
|
156
|
+
return self._cache[rel]
|
|
157
|
+
hit = None
|
|
158
|
+
for p, k in self._paths:
|
|
159
|
+
if rel == p or rel.startswith(p + "/"):
|
|
160
|
+
hit = k
|
|
161
|
+
break
|
|
162
|
+
self._cache[rel] = hit
|
|
163
|
+
return hit
|
|
164
|
+
|
|
165
|
+
def sees(self, caller_rel: str, callee_rel: str) -> bool:
|
|
166
|
+
"""May code in `caller_rel` name a declaration of `callee_rel`?"""
|
|
167
|
+
m = self.module_of(caller_rel)
|
|
168
|
+
if m is None:
|
|
169
|
+
return True
|
|
170
|
+
dm = self.module_of(callee_rel)
|
|
171
|
+
return dm is not None and dm in self.visible.get(m, {m})
|
|
172
|
+
|
|
173
|
+
def __bool__(self):
|
|
174
|
+
return bool(self.targets)
|