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
codegraph/viz/server.py
ADDED
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
"""Local web UI over a code-graph DB: `python -m codegraph.cli serve --db out/combined.db [--port 8177]`.
|
|
2
|
+
|
|
3
|
+
Stdlib HTTP server, read-only. Static page + vendored Cytoscape.js/fcose (no CDN). JSON API:
|
|
4
|
+
/api/search?q=&kind=&fuzzy=1 node lookup (fuzzy: the query's characters in order)
|
|
5
|
+
/api/stats node / edge counts by kind, entry points by kind, edges by confidence (landing page)
|
|
6
|
+
/api/graph?mode=&spec=&spec=&min_conf=&sinks= subgraph = union of the query's evidence paths
|
|
7
|
+
/api/node?id= docblock, file:line, source snippet, in/out edges with evidence
|
|
8
|
+
/api/presets canned queries: --presets FILE or .cg.yaml viz.presets, the sample-app presets that
|
|
9
|
+
resolve in this graph, and starter queries derived from the graph
|
|
10
|
+
/api/graph?mode=plan&spec=<plan>[&verify=1] planned-change overlay (plans/<name>.yaml) + check report
|
|
11
|
+
/api/plans plan files
|
|
12
|
+
"""
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import json
|
|
16
|
+
import mimetypes
|
|
17
|
+
import threading
|
|
18
|
+
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
|
19
|
+
from pathlib import Path
|
|
20
|
+
from urllib.parse import parse_qs, urlparse
|
|
21
|
+
|
|
22
|
+
from ..core.store import GraphStore
|
|
23
|
+
from . import graph as G
|
|
24
|
+
|
|
25
|
+
STATIC = Path(__file__).parent / "static"
|
|
26
|
+
# Canned queries for the bundled sample apps (examples/bookstore-*), shown when they resolve in the served graph. Your
|
|
27
|
+
# own project: .cg.yaml `viz.presets` or `serve --presets presets.json` (a JSON list of {id, label, mode, specs[, sinks]});
|
|
28
|
+
# starter queries derived from the graph (codegraph/starters.py) are always offered after them.
|
|
29
|
+
PRESETS = [
|
|
30
|
+
{"id": "warehouse_reaches", "label": "what reaches the warehouse connection / warehouse_stock (runtime vs operator vs gated)",
|
|
31
|
+
"mode": "reaches", "specs": ["connection:warehouse", "table:warehouse_stock"]},
|
|
32
|
+
{"id": "report_page_tables", "label": "report page -> backend -> tables (columns folded per table)", "mode": "downstream",
|
|
33
|
+
"specs": ["page:/reports/:id"], "sinks": ["table", "column"]},
|
|
34
|
+
{"id": "report_page_orders", "label": "path: report page -> ReportController::top -> table orders",
|
|
35
|
+
"mode": "path", "specs": ["page:/reports/:id", "ReportController::top", "table:orders"]},
|
|
36
|
+
{"id": "timezone_inputs", "label": "who reads request key 'timezone' (incl. resolutions)", "mode": "reaches",
|
|
37
|
+
"specs": ["request_key:timezone"]},
|
|
38
|
+
{"id": "plan_preorders", "label": "PLAN overlay: pre-orders (planned vs real graph, uncovered siblings)", "mode": "plan",
|
|
39
|
+
"specs": ["preorders"]},
|
|
40
|
+
{"id": "impact_report_top", "label": "impact of ReportController::top", "mode": "impact",
|
|
41
|
+
"specs": ["ReportController::top"]},
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class App:
|
|
46
|
+
def __init__(self, db: str, roots: dict[str, str] | None = None, plans: str | None = None, presets: str | None = None):
|
|
47
|
+
self.db = db
|
|
48
|
+
self.plans = plans
|
|
49
|
+
self.presets_file = presets
|
|
50
|
+
self.local = threading.local()
|
|
51
|
+
self.sources = G.Sources(GraphStore(db), roots)
|
|
52
|
+
self._presets = None
|
|
53
|
+
|
|
54
|
+
def st(self) -> GraphStore:
|
|
55
|
+
if not hasattr(self.local, "st"):
|
|
56
|
+
self.local.st = GraphStore(self.db)
|
|
57
|
+
return self.local.st
|
|
58
|
+
|
|
59
|
+
def api(self, path: str, qs: dict) -> object:
|
|
60
|
+
one = lambda k, d=None: (qs.get(k) or [d])[0] # noqa: E731
|
|
61
|
+
if path == "/api/search":
|
|
62
|
+
return G.search(self.st(), one("q", ""), one("kind") or None, int(one("limit", 30)), fuzzy=one("fuzzy") == "1")
|
|
63
|
+
if path == "/api/stats":
|
|
64
|
+
return G.stats(self.st())
|
|
65
|
+
if path == "/api/graph" and one("mode") == "plan":
|
|
66
|
+
return G.build_plan(self.st(), (qs.get("spec") or [""])[0], self.plans, verify=one("verify") == "1")
|
|
67
|
+
if path == "/api/plans":
|
|
68
|
+
from .. import plans as P
|
|
69
|
+
return P.list_plans(self.plans)
|
|
70
|
+
if path == "/api/graph":
|
|
71
|
+
sinks = [s for s in (one("sinks") or "").split(",") if s] or None
|
|
72
|
+
return G.build(self.st(), one("mode", "reaches"), qs.get("spec") or [], one("min_conf", "heuristic"), sinks)
|
|
73
|
+
if path == "/api/node":
|
|
74
|
+
return G.node_detail(self.st(), self.sources, one("id", ""))
|
|
75
|
+
if path == "/api/presets":
|
|
76
|
+
if self._presets is None:
|
|
77
|
+
self._presets = menu(self.st(), self.presets_file, self.plans)
|
|
78
|
+
return self._presets
|
|
79
|
+
if path == "/api/meta":
|
|
80
|
+
m = self.st().meta()
|
|
81
|
+
return {"project": m.get("project"), "repos": m.get("repos"), "indexed_at": m.get("indexed_at"), "db": self.db}
|
|
82
|
+
raise KeyError(path)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def _resolves(st: GraphStore, p: dict, plans: str | None) -> bool:
|
|
86
|
+
from .. import query as Q
|
|
87
|
+
if p.get("mode") == "plan":
|
|
88
|
+
from .. import plans as P
|
|
89
|
+
try:
|
|
90
|
+
return all(P.find_plan(s, plans) for s in p.get("specs") or [])
|
|
91
|
+
except P.PlanError:
|
|
92
|
+
return False
|
|
93
|
+
return bool(p.get("specs")) and all(Q.resolve_targets(st, s) for s in p["specs"])
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def menu(st: GraphStore, presets_file: str | None = None, plans: str | None = None) -> list[dict]:
|
|
97
|
+
"""Preset menu: the project's presets (--presets FILE, else .cg.yaml viz.presets), then the sample-app presets that
|
|
98
|
+
resolve in this graph, then the starter queries derived from it. Each entry carries `source`."""
|
|
99
|
+
from ..config import graph_configs
|
|
100
|
+
from ..starters import for_graph
|
|
101
|
+
own, src = [], None
|
|
102
|
+
if presets_file:
|
|
103
|
+
own, src = json.loads(Path(presets_file).read_text()), "--presets"
|
|
104
|
+
else:
|
|
105
|
+
for _, cfg, _ in graph_configs(st):
|
|
106
|
+
if (cfg.get("viz") or {}).get("presets"):
|
|
107
|
+
own, src = cfg["viz"]["presets"], cfg.get("file", ".cg.yaml")
|
|
108
|
+
break
|
|
109
|
+
out = [dict(p, source=src) for p in own]
|
|
110
|
+
out += [dict(p, source="examples") for p in PRESETS if _resolves(st, p, plans)]
|
|
111
|
+
out += [dict(p, source="starter") for p in for_graph(st)]
|
|
112
|
+
seen, menu_ = set(), []
|
|
113
|
+
for p in out:
|
|
114
|
+
if p.get("id") not in seen:
|
|
115
|
+
seen.add(p.get("id"))
|
|
116
|
+
menu_.append(p)
|
|
117
|
+
return menu_
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
def make_handler(app: App):
|
|
121
|
+
class H(BaseHTTPRequestHandler):
|
|
122
|
+
def log_message(self, fmt, *args): # quiet
|
|
123
|
+
pass
|
|
124
|
+
|
|
125
|
+
def _send(self, code, body: bytes, ctype="application/json"):
|
|
126
|
+
self.send_response(code)
|
|
127
|
+
self.send_header("Content-Type", ctype)
|
|
128
|
+
self.send_header("Content-Length", str(len(body)))
|
|
129
|
+
self.send_header("Cache-Control", "no-store")
|
|
130
|
+
self.end_headers()
|
|
131
|
+
self.wfile.write(body)
|
|
132
|
+
|
|
133
|
+
def do_GET(self): # noqa: N802
|
|
134
|
+
u = urlparse(self.path)
|
|
135
|
+
if u.path.startswith("/api/"):
|
|
136
|
+
try:
|
|
137
|
+
res = app.api(u.path, parse_qs(u.query))
|
|
138
|
+
self._send(200, json.dumps(res, default=str).encode())
|
|
139
|
+
except KeyError:
|
|
140
|
+
self._send(404, b'{"error":"not found"}')
|
|
141
|
+
except Exception as e: # noqa: BLE001
|
|
142
|
+
self._send(400, json.dumps({"error": str(e)}).encode())
|
|
143
|
+
return
|
|
144
|
+
rel = "index.html" if u.path in ("/", "") else u.path.lstrip("/")
|
|
145
|
+
p = (STATIC / rel).resolve()
|
|
146
|
+
if not str(p).startswith(str(STATIC.resolve())) or not p.is_file():
|
|
147
|
+
self._send(404, b"not found", "text/plain")
|
|
148
|
+
return
|
|
149
|
+
self._send(200, p.read_bytes(), mimetypes.guess_type(p.name)[0] or "application/octet-stream")
|
|
150
|
+
return H
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def serve(db: str, host="127.0.0.1", port=8177, roots: dict[str, str] | None = None, plans: str | None = None,
|
|
154
|
+
presets: str | None = None):
|
|
155
|
+
app = App(str(Path(db).resolve()), roots, plans, presets)
|
|
156
|
+
httpd = ThreadingHTTPServer((host, port), make_handler(app))
|
|
157
|
+
print(f"code-graph view: http://{host}:{port}/ (db {app.db}; Ctrl-C to stop)", flush=True)
|
|
158
|
+
try:
|
|
159
|
+
httpd.serve_forever()
|
|
160
|
+
except KeyboardInterrupt:
|
|
161
|
+
pass
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def export_plan_html(db: str, out: str, plan: str, plans_root=None, verify=False) -> str:
|
|
165
|
+
"""Self-contained HTML of a plan overlay (same view as mode=plan in `serve`)."""
|
|
166
|
+
st = GraphStore(db)
|
|
167
|
+
g = G.build_plan(st, plan, plans_root, verify=verify)
|
|
168
|
+
return _write_html(st, g, out, f"plan {g['meta']['plan']}: {g['meta']['title']}")
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def export_html(db: str, out: str, mode: str, specs: list[str], min_conf="heuristic", sinks=None, title=None) -> str:
|
|
172
|
+
"""Self-contained HTML (data + vendored JS inlined) for one query; opens from disk without a server."""
|
|
173
|
+
st = GraphStore(db)
|
|
174
|
+
g = G.build(st, mode, specs, min_conf, sinks)
|
|
175
|
+
return _write_html(st, g, out, title or f"{mode} {' '.join(specs)}")
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _write_html(st: GraphStore, g: dict, out: str, title: str) -> str:
|
|
179
|
+
src = G.Sources(st)
|
|
180
|
+
details = {n["id"]: G.node_detail(st, src, n["id"], limit=12) for n in g["nodes"] if st.node(n["id"])}
|
|
181
|
+
for d in details.values(): # no local paths in a file meant to be shared
|
|
182
|
+
if d and d.get("snippet"):
|
|
183
|
+
d["snippet"].pop("abs", None)
|
|
184
|
+
html = (STATIC / "index.html").read_text()
|
|
185
|
+
for name in ("cytoscape.min.js", "layout-base.js", "cose-base.js", "cytoscape-fcose.js"):
|
|
186
|
+
js = (STATIC / "vendor" / name).read_text().replace("</script", "<\\/script")
|
|
187
|
+
html = html.replace(f'<script src="vendor/{name}"></script>', f"<script>{js}</script>")
|
|
188
|
+
js = (STATIC / "layered.js").read_text().replace("</script", "<\\/script")
|
|
189
|
+
html = html.replace('<script src="layered.js"></script>', f"<script>{js}</script>")
|
|
190
|
+
css = (STATIC / "app.css").read_text()
|
|
191
|
+
html = html.replace('<link rel="stylesheet" href="app.css">', f"<style>{css}</style>")
|
|
192
|
+
data = json.dumps({"graph": g, "details": details, "title": title}, default=str)
|
|
193
|
+
app_js = (STATIC / "app.js").read_text().replace("</script", "<\\/script")
|
|
194
|
+
data = data.replace("</", "<\\/")
|
|
195
|
+
html = html.replace('<script src="app.js"></script>', f"<script>window.__STATIC__ = {data};</script><script>{app_js}</script>")
|
|
196
|
+
Path(out).parent.mkdir(parents=True, exist_ok=True)
|
|
197
|
+
Path(out).write_text(html)
|
|
198
|
+
return out
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
* { box-sizing: border-box; }
|
|
2
|
+
:root { --panel: 420px; --hdr: 52px; }
|
|
3
|
+
@media (max-width: 1440px) { :root { --panel: 360px; } }
|
|
4
|
+
html, body { margin: 0; height: 100%; font: 13px/1.35 -apple-system, "Segoe UI", Roboto, "Noto Sans", sans-serif; color: #1d2330; background: #f6f7f9; }
|
|
5
|
+
header { position: relative; height: var(--hdr); display: flex; align-items: center; gap: 8px; padding: 0 10px; background: #1d2330; color: #fff; white-space: nowrap; }
|
|
6
|
+
header .brand { font-weight: 700; letter-spacing: .3px; color: #fff; text-decoration: none; flex: none; }
|
|
7
|
+
header .grp { display: flex; align-items: center; gap: 6px; flex: none; }
|
|
8
|
+
header .grp.query { flex: 1 1 auto; min-width: 0; }
|
|
9
|
+
header select, header input, header button { height: 30px; border-radius: 5px; border: 1px solid #3a4256; background: #2a3142; color: #fff; padding: 0 8px; font-size: 12.5px; white-space: nowrap; flex: none; }
|
|
10
|
+
header button { background: #3d6be0; border-color: #3d6be0; cursor: pointer; }
|
|
11
|
+
header .view button, header button.more { background: #2a3142; border-color: #3a4256; }
|
|
12
|
+
header .specbox { flex: 1 1 auto; min-width: 0; } header .specbox input { width: 100%; }
|
|
13
|
+
header button.more { display: none; font-size: 16px; line-height: 1; padding: 0 10px; }
|
|
14
|
+
@media (max-width: 1439px) {
|
|
15
|
+
header button.more { display: inline-block; }
|
|
16
|
+
header .grp.view { display: none; position: absolute; top: calc(var(--hdr) - 4px); right: 8px; z-index: 20; flex-direction: column; align-items: stretch;
|
|
17
|
+
padding: 8px; background: #1d2330; border: 1px solid #3a4256; border-radius: 6px; box-shadow: 0 4px 14px rgba(0,0,0,.25); }
|
|
18
|
+
header .grp.view.open { display: flex; }
|
|
19
|
+
}
|
|
20
|
+
main { position: absolute; top: var(--hdr); bottom: 0; left: 0; right: 0; }
|
|
21
|
+
#cy { position: absolute; top: 34px; bottom: 0; left: 0; right: var(--panel); background: #fff; }
|
|
22
|
+
#cy:focus { outline: none; } #cy:focus-visible { outline: 2px solid #3d6be0; outline-offset: -2px; }
|
|
23
|
+
#panel { position: absolute; top: 0; bottom: 0; right: 0; width: var(--panel); border-left: 1px solid #dde1e8; background: #fbfcfd; }
|
|
24
|
+
#panelbody { position: absolute; inset: 0; overflow: auto; padding: 0 14px 12px 16px; }
|
|
25
|
+
#panel .hint { color: #5c6577; }
|
|
26
|
+
#panel h2 { font-size: 15px; margin: 0 0 4px; word-break: break-all; }
|
|
27
|
+
#panel .kind { display: inline-block; padding: 1px 7px; border-radius: 9px; color: #fff; font-size: 11px; margin-right: 6px; }
|
|
28
|
+
#panel .loc { font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 12px; color: #2f4b9a; word-break: break-all; }
|
|
29
|
+
#panel pre { background: #f0f2f6; padding: 8px; border-radius: 5px; overflow: auto; font-size: 11.5px; white-space: pre-wrap; }
|
|
30
|
+
#panel pre.code { white-space: pre; }
|
|
31
|
+
#panel pre.code .hl { background: #ffe9a8; display: block; }
|
|
32
|
+
#panel table { border-collapse: collapse; width: 100%; font-size: 11.5px; }
|
|
33
|
+
#panel td { border-top: 1px solid #e6e9ef; padding: 3px 4px; vertical-align: top; word-break: break-all; }
|
|
34
|
+
#panel td.k { white-space: nowrap; color: #5c6577; word-break: normal; }
|
|
35
|
+
#panel h3 { font-size: 12.5px; margin: 14px 0 4px; color: #384156; letter-spacing: .2px; }
|
|
36
|
+
#panel .badge { display: inline-block; border: 1px solid #c7cdd8; border-radius: 4px; padding: 0 5px; margin: 1px 3px 1px 0; font-size: 11px; background: #fff; }
|
|
37
|
+
#panel .badge.gated { border-color: #d64545; color: #b02a2a; }
|
|
38
|
+
#panel .badge.live { border-color: #2e9d57; color: #1e7a41; }
|
|
39
|
+
#panel a { color: #2f4b9a; cursor: pointer; text-decoration: none; } #panel a:hover { text-decoration: underline; }
|
|
40
|
+
#status { position: absolute; left: 0; top: 0; right: var(--panel); height: 34px; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; background: #f6f7f9; border-bottom: 1px solid #dde1e8; padding: 8px 10px; font-size: 12px; line-height: 1.3; }
|
|
41
|
+
#status b { color: #1d2330; }
|
|
42
|
+
#legendbox { position: absolute; left: 10px; bottom: 10px; max-width: calc(100% - var(--panel) - 20px); z-index: 5; background: rgba(255,255,255,.95); border: 1px solid #dde1e8; border-radius: 6px; font-size: 11.5px; }
|
|
43
|
+
#legendbox summary { cursor: pointer; padding: 4px 10px; color: #384156; font-weight: 600; }
|
|
44
|
+
#legend { padding: 4px 10px 8px; display: flex; flex-wrap: wrap; gap: 3px 12px; max-height: 40vh; overflow: auto; }
|
|
45
|
+
#legend .sw { display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin-right: 3px; vertical-align: -1px; }
|
|
46
|
+
#legend .ln { display: inline-block; width: 26px; height: 0; border-top: 2px solid #555; margin-right: 4px; vertical-align: 3px; }
|
|
47
|
+
#fitall { position: absolute; top: 44px; right: calc(var(--panel) + 10px); z-index: 6; height: 28px; border-radius: 5px; border: 1px solid #3d6be0; background: #fff; color: #2f4b9a; font-size: 12px; cursor: pointer; padding: 0 10px; }
|
|
48
|
+
#tip { position: fixed; z-index: 30; pointer-events: none; max-width: 420px; background: #1d2330; color: #fff; border-radius: 5px; padding: 5px 8px; font-size: 12px; line-height: 1.35; box-shadow: 0 2px 8px rgba(0,0,0,.25); }
|
|
49
|
+
#tip .loc { font-family: ui-monospace, Menlo, Consolas, monospace; color: #c9d3ea; word-break: break-all; }
|
|
50
|
+
/* landing page: overview, search, starter queries */
|
|
51
|
+
#landing { position: absolute; top: 0; left: 0; bottom: 0; right: var(--panel); overflow: auto; background: #f6f7f9; padding: 28px 32px; z-index: 4; }
|
|
52
|
+
#landing h1 { font-size: 20px; margin: 0 0 2px; } #landing .sub { color: #5c6577; margin-bottom: 18px; }
|
|
53
|
+
#landing .stats { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 18px; }
|
|
54
|
+
#landing .stat { background: #fff; border: 1px solid #dde1e8; border-radius: 8px; padding: 10px 14px; min-width: 150px; }
|
|
55
|
+
#landing .stat .n { font-size: 20px; font-weight: 700; } #landing .stat .l { color: #5c6577; font-size: 12px; }
|
|
56
|
+
#landing .stat .kinds { color: #384156; font-size: 12px; margin-top: 4px; white-space: normal; max-width: 320px; }
|
|
57
|
+
#landing .search { position: relative; max-width: 760px; margin-bottom: 8px; }
|
|
58
|
+
#landing .search input { width: 100%; height: 44px; font-size: 16px; padding: 0 14px; border-radius: 8px; border: 1px solid #b9c2d3; background: #fff; }
|
|
59
|
+
#landing .search input:focus { outline: 2px solid #3d6be0; outline-offset: 0; border-color: #3d6be0; }
|
|
60
|
+
#landing .chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 8px 0 4px; }
|
|
61
|
+
#landing .chip { border: 1px solid #b9c2d3; border-radius: 14px; background: #fff; padding: 2px 10px; font-size: 12px; cursor: pointer; color: #384156; }
|
|
62
|
+
#landing .chip[aria-pressed="true"] { background: #1d2330; color: #fff; border-color: #1d2330; }
|
|
63
|
+
#landing .hits { list-style: none; margin: 0; padding: 0; max-width: 760px; background: #fff; border: 1px solid #dde1e8; border-radius: 8px; }
|
|
64
|
+
#landing .hits:empty { display: none; }
|
|
65
|
+
#landing .hits li { padding: 6px 12px; border-top: 1px solid #eef0f4; cursor: pointer; display: flex; gap: 10px; align-items: baseline; }
|
|
66
|
+
#landing .hits li:first-child { border-top: 0; }
|
|
67
|
+
#landing .hits li[aria-selected="true"] { background: #e8eefc; }
|
|
68
|
+
#landing .hits .k { color: #5c6577; font-size: 11.5px; min-width: 70px; } #landing .hits .nm { font-weight: 600; }
|
|
69
|
+
#landing .hits .f { color: #5c6577; font-family: ui-monospace, Menlo, Consolas, monospace; font-size: 11.5px; overflow: hidden; text-overflow: ellipsis; }
|
|
70
|
+
#landing .hits .q { margin-left: auto; color: #2f4b9a; font-size: 11.5px; white-space: nowrap; }
|
|
71
|
+
#landing h2 { font-size: 14px; margin: 22px 0 8px; color: #384156; }
|
|
72
|
+
#landing .cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 10px; max-width: 1100px; }
|
|
73
|
+
#landing .card { text-align: left; background: #fff; border: 1px solid #dde1e8; border-radius: 8px; padding: 10px 12px; cursor: pointer; font: inherit; color: inherit; }
|
|
74
|
+
#landing .card:hover, #landing .card:focus-visible { border-color: #3d6be0; outline: none; box-shadow: 0 0 0 2px rgba(61,107,224,.25); }
|
|
75
|
+
#landing .card .t { font-weight: 600; margin-bottom: 3px; } #landing .card .w { color: #5c6577; font-size: 12px; }
|
|
76
|
+
#landing .card code { display: block; margin-top: 6px; font-size: 11px; color: #2f4b9a; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
|
|
77
|
+
#panel .planbox { margin: 6px 0; padding: 6px 8px; border-radius: 5px; border-left: 4px solid #8a93a6; background: #f3f4f7; }
|
|
78
|
+
#panel .planbox.p-missing { border-color: #d6006b; background: #fff0f6; } #panel .planbox.p-modified { border-color: #f59f00; background: #fff8e6; }
|
|
79
|
+
#panel .planbox.p-added { border-color: #2e9d57; background: #eefaf2; } #panel .planbox.p-forbidden { border-color: #d62828; background: #fff0f0; }
|
|
80
|
+
#panel .planbox.p-review { border-color: #b06ab3; } #panel .planbox.p-covered { border-color: #2e9d57; }
|
|
81
|
+
#panel pre.report { font-size: 10.5px; white-space: pre-wrap; }
|
|
82
|
+
#legend .chip { font: inherit; color: #1d2330; background: #fff; border: 1px solid #7d889c; border-radius: 10px; padding: 0 7px; cursor: pointer; }
|
|
83
|
+
#legend .chip[data-conf][aria-pressed="false"] { opacity: .5; text-decoration: line-through; }
|
|
84
|
+
#legend .kchip[aria-pressed="true"] { border: 2px solid #1d4ed8; font-weight: 600; }
|
|
85
|
+
#legend .chip:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 1px; }
|
|
86
|
+
#help { position: absolute; top: 60px; left: 50%; transform: translateX(-50%); z-index: 20; background: #fff; color: #1d2330; border: 1px solid #7d889c; border-radius: 8px; padding: 12px 16px; box-shadow: 0 6px 24px rgba(0,0,0,.18); font-size: 13px; }
|
|
87
|
+
#help table { border-collapse: collapse; margin-top: 6px; } #help td { padding: 3px 10px 3px 0; vertical-align: top; }
|
|
88
|
+
#help kbd { border: 1px solid #7d889c; border-radius: 3px; padding: 0 4px; font-size: 12px; background: #f6f7f9; }
|
|
89
|
+
#helpclose { position: absolute; top: 4px; right: 6px; border: 0; background: none; font-size: 18px; cursor: pointer; color: #384156; }
|
|
90
|
+
#cy:focus-visible { outline: 3px solid #1d4ed8; outline-offset: -3px; }
|
|
91
|
+
#phandle { position: absolute; left: -4px; top: 0; bottom: 0; width: 8px; cursor: col-resize; z-index: 3; }
|
|
92
|
+
#phandle:hover, #phandle:focus-visible { background: rgba(29,78,216,.25); outline: none; }
|
|
93
|
+
#pcollapse { position: absolute; top: 6px; right: 6px; z-index: 4; width: 24px; height: 24px; border: 1px solid #7d889c; border-radius: 4px; background: #fff; cursor: pointer; color: #1d2330; }
|
|
94
|
+
body.pcollapsed #panelbody { display: none; }
|
|
95
|
+
#panel .phead { position: sticky; top: 0; background: #fbfcfd; padding: 12px 28px 6px 0; border-bottom: 1px solid #e6e9ef; z-index: 2; }
|
|
96
|
+
#panel .pacts { margin-top: 4px; }
|
|
97
|
+
#panel .pbtn { display: inline-block; font: inherit; font-size: 11px; color: #1d2330; background: #fff; border: 1px solid #7d889c; border-radius: 4px; padding: 1px 6px; margin: 2px 3px 0 0; cursor: pointer; text-decoration: none; }
|
|
98
|
+
#panel .pbtn:focus-visible, #ctxmenu button:focus-visible { outline: 2px solid #1d4ed8; outline-offset: 1px; }
|
|
99
|
+
#panel h3.src { display: flex; gap: 6px; align-items: baseline; } #panel h3.src .loc { flex: 1; min-width: 0; overflow: hidden; white-space: nowrap; }
|
|
100
|
+
#panel pre.code { overflow-x: auto; } #panel pre.code.wrap { white-space: pre-wrap; }
|
|
101
|
+
#panel details.egrp { margin: 2px 0 2px 4px; } #panel details.egrp summary { cursor: pointer; font-size: 12px; color: #384156; font-weight: 600; }
|
|
102
|
+
#panel .summary { margin: 8px 0; padding: 6px 8px; border: 1px solid #dde1e8; border-radius: 6px; background: #fff; }
|
|
103
|
+
#panel .summary h3 { margin-top: 0; } #panel table.bydepth td { text-align: center; } #panel table.bydepth td.k { text-align: left; }
|
|
104
|
+
#ctxmenu { position: fixed; z-index: 30; background: #fff; border: 1px solid #7d889c; border-radius: 6px; box-shadow: 0 4px 16px rgba(0,0,0,.18); padding: 4px 0; display: flex; flex-direction: column; }
|
|
105
|
+
#ctxmenu[hidden] { display: none; }
|
|
106
|
+
#ctxmenu button { font: inherit; font-size: 12.5px; text-align: left; border: 0; background: none; padding: 5px 14px; cursor: pointer; color: #1d2330; }
|
|
107
|
+
#ctxmenu button:hover { background: #eef1f6; }
|
|
108
|
+
/* dark theme (#82 item 13): data-theme="dark" on <html>, from prefers-color-scheme or the theme button */
|
|
109
|
+
:root[data-theme="dark"] { color-scheme: dark; }
|
|
110
|
+
:root[data-theme="dark"] body { color: #e6e9ef; background: #0d1117; }
|
|
111
|
+
:root[data-theme="dark"] #cy { background: #12161d; }
|
|
112
|
+
:root[data-theme="dark"] #status { background: #161b23; border-color: #2a3140; color: #c3cad6; }
|
|
113
|
+
:root[data-theme="dark"] #status b { color: #e6e9ef; }
|
|
114
|
+
:root[data-theme="dark"] #panel, :root[data-theme="dark"] #panel .phead { background: #161b23; border-color: #2a3140; }
|
|
115
|
+
:root[data-theme="dark"] #panel .hint, :root[data-theme="dark"] #panel td.k { color: #a8b0bf; }
|
|
116
|
+
:root[data-theme="dark"] #panel h3, :root[data-theme="dark"] #panel details.egrp summary { color: #c3cad6; }
|
|
117
|
+
:root[data-theme="dark"] #panel .loc, :root[data-theme="dark"] #panel a { color: #8fb3ff; }
|
|
118
|
+
:root[data-theme="dark"] #panel pre { background: #0d1117; color: #e6e9ef; }
|
|
119
|
+
:root[data-theme="dark"] #panel pre.code .hl { background: #4a3d10; }
|
|
120
|
+
:root[data-theme="dark"] #panel td { border-color: #2a3140; }
|
|
121
|
+
:root[data-theme="dark"] #panel .badge, :root[data-theme="dark"] #panel .pbtn, :root[data-theme="dark"] #panel .summary,
|
|
122
|
+
:root[data-theme="dark"] #legend .chip, :root[data-theme="dark"] #pcollapse { background: #1c222c; color: #e6e9ef; border-color: #8792a6; }
|
|
123
|
+
:root[data-theme="dark"] #legendbox { background: rgba(22,27,35,.96); border-color: #2a3140; }
|
|
124
|
+
:root[data-theme="dark"] #legendbox summary { color: #c3cad6; }
|
|
125
|
+
:root[data-theme="dark"] #fitall { background: #1c222c; color: #8fb3ff; border-color: #7aa7ff; }
|
|
126
|
+
:root[data-theme="dark"] #help, :root[data-theme="dark"] #ctxmenu { background: #161b23; color: #e6e9ef; border-color: #8792a6; }
|
|
127
|
+
:root[data-theme="dark"] #help kbd { background: #1c222c; border-color: #8792a6; }
|
|
128
|
+
:root[data-theme="dark"] #helpclose, :root[data-theme="dark"] #ctxmenu button { color: #e6e9ef; }
|
|
129
|
+
:root[data-theme="dark"] #ctxmenu button:hover { background: #222a36; }
|
|
130
|
+
:root[data-theme="dark"] #landing { background: #0d1117; }
|
|
131
|
+
:root[data-theme="dark"] #landing .stat, :root[data-theme="dark"] #landing .card, :root[data-theme="dark"] #landing .hits,
|
|
132
|
+
:root[data-theme="dark"] #landing .search input, :root[data-theme="dark"] #landing .chip { background: #161b23; border-color: #3a4256; color: #e6e9ef; }
|
|
133
|
+
:root[data-theme="dark"] #landing .sub, :root[data-theme="dark"] #landing .stat .l, :root[data-theme="dark"] #landing .card .w,
|
|
134
|
+
:root[data-theme="dark"] #landing .hits .k, :root[data-theme="dark"] #landing .hits .f { color: #a8b0bf; }
|
|
135
|
+
:root[data-theme="dark"] #landing .stat .kinds, :root[data-theme="dark"] #landing h2 { color: #c3cad6; }
|
|
136
|
+
:root[data-theme="dark"] #landing .hits li { border-color: #2a3140; } :root[data-theme="dark"] #landing .hits li[aria-selected="true"] { background: #1f2a44; }
|
|
137
|
+
:root[data-theme="dark"] #landing .hits .q { color: #8fb3ff; }
|
|
138
|
+
:root[data-theme="dark"] #landing .chip[aria-pressed="true"] { background: #e6e9ef; color: #12161d; }
|
|
139
|
+
:root[data-theme="dark"] #listview { background: #12161d; color: #e6e9ef; }
|
|
140
|
+
#listview { position: absolute; top: 34px; bottom: 0; left: 0; right: var(--panel); overflow: auto; background: #fff; z-index: 5; padding: 10px 16px; font-size: 13px; }
|
|
141
|
+
#listview[hidden] { display: none; }
|
|
142
|
+
#listview h3 { font-size: 13px; margin: 10px 0 4px; } #listview ul { margin: 0 0 0 4px; padding-left: 14px; }
|
|
143
|
+
#listview a { color: inherit; cursor: pointer; } #listview a:hover, #listview a:focus-visible { text-decoration: underline; }
|
|
144
|
+
#listview .k { color: #5c6577; font-size: 11.5px; margin-left: 6px; } :root[data-theme="dark"] #listview .k { color: #a8b0bf; }
|
|
145
|
+
#truncbanner { position: absolute; top: 40px; left: 50%; transform: translateX(-50%); z-index: 7; background: #fff4d6; color: #5c3d00; border: 1px solid #b26b00; border-radius: 6px; padding: 4px 12px; font-size: 12.5px; }
|
|
146
|
+
#truncbanner[hidden] { display: none; }
|
|
147
|
+
:root[data-theme="dark"] #truncbanner { background: #3a2c08; color: #ffd98a; border-color: #e09a2c; }
|
|
148
|
+
:root[data-theme="dark"] #landing .card code { color: #8fb3ff; }
|