@trebired/code-insights 0.0.0-stage → 0.1.0
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.
- package/.trebired/logger/config.ts +4 -0
- package/CHANGELOG.md +11 -0
- package/LICENSE +661 -0
- package/README.md +139 -2
- package/dist/client/controller.d.ts +31 -0
- package/dist/client/controller.d.ts.map +1 -0
- package/dist/client/controller.js +136 -0
- package/dist/client/controller.js.map +1 -0
- package/dist/client/index.d.ts +5 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +59 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/layout.d.ts +8 -0
- package/dist/client/layout.d.ts.map +1 -0
- package/dist/client/layout.js +30 -0
- package/dist/client/layout.js.map +1 -0
- package/dist/client/model.d.ts +27 -0
- package/dist/client/model.d.ts.map +1 -0
- package/dist/client/model.js +57 -0
- package/dist/client/model.js.map +1 -0
- package/dist/client/render.d.ts +20 -0
- package/dist/client/render.d.ts.map +1 -0
- package/dist/client/render.js +95 -0
- package/dist/client/render.js.map +1 -0
- package/dist/client/viewport.d.ts +12 -0
- package/dist/client/viewport.d.ts.map +1 -0
- package/dist/client/viewport.js +70 -0
- package/dist/client/viewport.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/react/code_map.d.ts +17 -0
- package/dist/react/code_map.d.ts.map +1 -0
- package/dist/react/code_map.js +36 -0
- package/dist/react/code_map.js.map +1 -0
- package/dist/react/hotspots.d.ts +12 -0
- package/dist/react/hotspots.d.ts.map +1 -0
- package/dist/react/hotspots.js +28 -0
- package/dist/react/hotspots.js.map +1 -0
- package/dist/react/index.d.ts +5 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +3 -0
- package/dist/react/index.js.map +1 -0
- package/dist/server/binary.d.ts +4 -0
- package/dist/server/binary.d.ts.map +1 -0
- package/dist/server/binary.js +46 -0
- package/dist/server/binary.js.map +1 -0
- package/dist/server/detect.d.ts +13 -0
- package/dist/server/detect.d.ts.map +1 -0
- package/dist/server/detect.js +15 -0
- package/dist/server/detect.js.map +1 -0
- package/dist/server/index.d.ts +10 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +6 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/logging.d.ts +4 -0
- package/dist/server/logging.d.ts.map +1 -0
- package/dist/server/logging.js +12 -0
- package/dist/server/logging.js.map +1 -0
- package/dist/server/map.d.ts +8 -0
- package/dist/server/map.d.ts.map +1 -0
- package/dist/server/map.js +81 -0
- package/dist/server/map.js.map +1 -0
- package/dist/server/process.d.ts +13 -0
- package/dist/server/process.d.ts.map +1 -0
- package/dist/server/process.js +58 -0
- package/dist/server/process.js.map +1 -0
- package/dist/server/scan.d.ts +30 -0
- package/dist/server/scan.d.ts.map +1 -0
- package/dist/server/scan.js +63 -0
- package/dist/server/scan.js.map +1 -0
- package/dist/shared/constants.d.ts +5 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +5 -0
- package/dist/shared/constants.js.map +1 -0
- package/dist/shared/copy.d.ts +40 -0
- package/dist/shared/copy.d.ts.map +1 -0
- package/dist/shared/copy.js +56 -0
- package/dist/shared/copy.js.map +1 -0
- package/dist/shared/types.d.ts +138 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +2 -0
- package/dist/shared/types.js.map +1 -0
- package/native/linux-arm64-gnu/code-insights +0 -0
- package/native/linux-x64-gnu/code-insights +0 -0
- package/native/vendor/hyperpolyglot/LICENSE-MIT +21 -0
- package/package.json +107 -4
package/README.md
CHANGED
|
@@ -1,3 +1,140 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @trebired/code-insights
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Repository insights for Bun applications, scanned by a native engine that reads a git repository directly: languages, the file tree, a file import graph, a function call graph and hotspots, with live progress, plus an interactive code map and hotspot list for `@trebired/frontend`.
|
|
4
|
+
|
|
5
|
+
The package owns reading the repository at a ref, language detection, line counts, vendored and generated file rules, the tree, import resolution, call resolution, churn, the progress stream, the result format, the code map data, and the code map and hotspot interface. The application owns where repositories live, when a scan runs, where results are stored, who may see them, and the routes that serve them. The package does not own a job queue, storage, permissions, or any HTTP route.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
Runtime support: Bun 1+.
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
bun i @trebired/code-insights
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { buildCodeMapData, scanRepository } from "@trebired/code-insights/server";
|
|
19
|
+
|
|
20
|
+
const result = await scanRepository({
|
|
21
|
+
gitDir: "/srv/repositories/app.git",
|
|
22
|
+
ref: "main",
|
|
23
|
+
onProgress: ({ phase, percent }) => broadcast("scan", { phase, percent }),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const files = buildCodeMapData(result, "file");
|
|
27
|
+
const functions = buildCodeMapData(result, "function");
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { code_map, hotspot_list } from "@trebired/code-insights/react";
|
|
32
|
+
|
|
33
|
+
code_map({ dataUrl: "/repository/insights/graph", hrefTemplate: "/repository/edit?path={path}&line={line}", lang });
|
|
34
|
+
hotspot_list({ hotspots: result.hotspots, hrefFor: (path) => `/repository/edit?path=${encodeURIComponent(path)}`, lang });
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
import { bindCodeMaps } from "@trebired/code-insights/client";
|
|
39
|
+
|
|
40
|
+
bindCodeMaps(document);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Concepts
|
|
44
|
+
|
|
45
|
+
### Engine
|
|
46
|
+
|
|
47
|
+
The scan runs in a separate native process, not in the application's process. It reads the ref with the `git` command line, streams every blob through one `git cat-file --batch` process, and parses files in parallel. A crash, a huge repository or a cancelled scan never takes the application down, and the scan never blocks its event loop.
|
|
48
|
+
|
|
49
|
+
### Phases
|
|
50
|
+
|
|
51
|
+
A scan runs these phases in order. Each one reports `{ phase, done, total, percent }` while it runs, and `percent` is the share of the whole scan, weighted by phase.
|
|
52
|
+
|
|
53
|
+
| Phase | Result |
|
|
54
|
+
| --- | --- |
|
|
55
|
+
| `listing` | the commit and every tree entry |
|
|
56
|
+
| `languages` | `languages`, `files`, `totals`, `unknown`, `skipped` |
|
|
57
|
+
| `tree` | `tree.nested` and `tree.ascii` |
|
|
58
|
+
| `imports` | `imports`: files as nodes, resolved imports as edges |
|
|
59
|
+
| `functions` | `functions`: definitions as nodes, resolved calls as edges |
|
|
60
|
+
| `hotspots` | `hotspots`: code lines times commits that touched the file |
|
|
61
|
+
|
|
62
|
+
`phases` limits a scan to the phases it names. `listing` always runs, `functions` brings `imports` with it, and `imports` and `hotspots` bring `languages`.
|
|
63
|
+
|
|
64
|
+
### Languages
|
|
65
|
+
|
|
66
|
+
Detection follows GitHub Linguist's rules: file names, extensions, shebangs, heuristics and the classifier, with Linguist's colours and language types. Files are left out of the totals when they are binary, vendored (`node_modules`, `dist`, `vendor` and the rest of Linguist's list), generated (lockfiles, minified files, source maps, a generated header) or documentation. `.gitattributes` overrides all of these with `linguist-vendored`, `linguist-generated`, `linguist-documentation` and `linguist-language`.
|
|
67
|
+
|
|
68
|
+
### Import Resolution
|
|
69
|
+
|
|
70
|
+
Imports resolve to files in the same repository. Package imports count as external, and imports that point inside the repository but match no file count as unresolved, with up to 50 samples in `imports.unresolved_samples`.
|
|
71
|
+
|
|
72
|
+
- TypeScript and JavaScript: relative paths, extensions and `index` files, `.js` specifiers that name a `.ts` file, tsconfig `paths` and `baseUrl` through `extends`, package.json `imports`, and Code Discipline alias maps in `.trebired/code-discipline/imports/*.json`.
|
|
73
|
+
- Python: relative imports, packages and modules from the importing file's directory upwards and from `src`.
|
|
74
|
+
- Rust: `mod` declarations, `#[path]` modules, `include!`, and `use` paths starting with `crate`, `self` or `super`.
|
|
75
|
+
- Go: import paths under a `go.mod` module, to every non-test file of the package.
|
|
76
|
+
|
|
77
|
+
### Call Resolution
|
|
78
|
+
|
|
79
|
+
A call becomes an edge only when the engine can name its target: a function in the same file, an imported function, a method on `this` or `self`, a method of a type through `Type::method` or `Self::method`, a Go receiver method or a function of the same Go package. Anything else counts as unresolved and draws no edge. Each edge carries how it was resolved (`local`, `import`, `member` or `package`) and how often the call appears.
|
|
80
|
+
|
|
81
|
+
### Code Map
|
|
82
|
+
|
|
83
|
+
`buildCodeMapData(result, level)` turns either graph into nodes grouped by folder, choosing a folder depth that gives a readable number of groups. The map starts with every folder collapsed into one node. Clicking a folder opens it, clicking a file or function highlights what it links to and what links to it, and clicking it again opens it through `hrefTemplate`. A cancellable `code-map:open` event fires first, so the application can take over the navigation.
|
|
84
|
+
|
|
85
|
+
## Configuration
|
|
86
|
+
|
|
87
|
+
### Limits
|
|
88
|
+
|
|
89
|
+
`scanRepository` takes `limits`:
|
|
90
|
+
|
|
91
|
+
| Option | Default | Effect |
|
|
92
|
+
| --- | --- | --- |
|
|
93
|
+
| `maxReadBytes` | 8 MB | larger files are counted by size only |
|
|
94
|
+
| `maxParseBytes` | 1 MB | larger files are not parsed for imports or calls |
|
|
95
|
+
| `maxImportEdges` | 50 000 | further edges are dropped and `imports.truncated` is set |
|
|
96
|
+
| `maxFunctionNodes` | 20 000 | further definitions are dropped and `functions.truncated` is set |
|
|
97
|
+
| `maxFunctionEdges` | 60 000 | the most frequent calls are kept |
|
|
98
|
+
| `historyCommits` | 1 000 | commits read for hotspots |
|
|
99
|
+
|
|
100
|
+
`buildCodeMapData` takes `maxNodes` (default 4 000) and keeps the most connected nodes of a larger graph.
|
|
101
|
+
|
|
102
|
+
## Runtime
|
|
103
|
+
|
|
104
|
+
### Engine Binary
|
|
105
|
+
|
|
106
|
+
The package ships the engine for Linux x64 and arm64 with glibc, in `native/<platform>/code-insights`. `TREBIRED_CODE_INSIGHTS_BINARY` points the package at another build. Other platforms fail with `code-insights-binary-missing`.
|
|
107
|
+
|
|
108
|
+
### Errors and Cancelling
|
|
109
|
+
|
|
110
|
+
Failures reject with `CodeInsightsError` and a `code`: `not-a-repository`, `ref-not-found`, `git-unavailable`, `aborted`, `engine-failed` or `result-version-mismatch`. Passing an `AbortSignal` kills the engine process.
|
|
111
|
+
|
|
112
|
+
### Logging
|
|
113
|
+
|
|
114
|
+
The package logs through `@trebired/logger-adapter` under `trebired.code-insights` and stays silent unless the application passes a logger.
|
|
115
|
+
|
|
116
|
+
### Third-Party Code
|
|
117
|
+
|
|
118
|
+
The engine contains hyperpolyglot (MIT OR Apache-2.0), vendored with its detectors made public and shipped with its licence in `native/vendor/hyperpolyglot/LICENSE-MIT`, which carries GitHub Linguist's language data (MIT), and Tree-sitter with its TypeScript, JavaScript, Python, Rust and Go grammars (MIT). The client uses d3-force (ISC).
|
|
119
|
+
|
|
120
|
+
## Public API
|
|
121
|
+
|
|
122
|
+
| Entry | Exports |
|
|
123
|
+
| --- | --- |
|
|
124
|
+
| `@trebired/code-insights` | `PACKAGE_NAME`, `RESULT_VERSION`, `SCAN_PHASES` and every result type |
|
|
125
|
+
| `@trebired/code-insights/server` | `scanRepository`, `detectLanguage`, `buildCodeMapData`, `resolveBinary`, `CodeInsightsError`, `BINARY_ENV` |
|
|
126
|
+
| `@trebired/code-insights/react` | `code_map`, `hotspot_list` |
|
|
127
|
+
| `@trebired/code-insights/client` | `bindCodeMaps`, `bindCodeMap`, `reloadCodeMaps` |
|
|
128
|
+
|
|
129
|
+
`detectLanguage({ path, content })` detects one file's language with the same rules as a scan. `reloadCodeMaps(scope)` fetches every bound map's data again at its current level, for after a rescan.
|
|
130
|
+
|
|
131
|
+
## What It Does Not Do
|
|
132
|
+
|
|
133
|
+
This package does not:
|
|
134
|
+
|
|
135
|
+
- queue, schedule, store or cache scans;
|
|
136
|
+
- serve routes or check who may see a repository;
|
|
137
|
+
- run on macOS, Windows or musl Linux without a custom engine build;
|
|
138
|
+
- resolve calls through variables, interfaces, callbacks or dynamic dispatch;
|
|
139
|
+
- parse languages other than TypeScript, JavaScript, Python, Rust and Go for imports and calls;
|
|
140
|
+
- count vendored, generated, binary or documentation files in language totals.
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CodeMapData, CodeMapLevel } from "../shared/types.d.ts";
|
|
2
|
+
import { type ViewGraph } from "./model.js";
|
|
3
|
+
import { type Rendered } from "./render.js";
|
|
4
|
+
import { type Transform } from "./viewport.js";
|
|
5
|
+
type MapState = {
|
|
6
|
+
canvas: SVGSVGElement;
|
|
7
|
+
data: CodeMapData | null;
|
|
8
|
+
filter: string;
|
|
9
|
+
graph: ViewGraph | null;
|
|
10
|
+
level: CodeMapLevel;
|
|
11
|
+
open: Set<string>;
|
|
12
|
+
positions: Map<string, {
|
|
13
|
+
x: number;
|
|
14
|
+
y: number;
|
|
15
|
+
}>;
|
|
16
|
+
rendered: Rendered | null;
|
|
17
|
+
root: HTMLElement;
|
|
18
|
+
selected: string | null;
|
|
19
|
+
status: HTMLElement | null;
|
|
20
|
+
transform: Transform;
|
|
21
|
+
};
|
|
22
|
+
declare function refreshHighlight(state: MapState): void;
|
|
23
|
+
declare function draw(state: MapState, refit: boolean): void;
|
|
24
|
+
declare function load(state: MapState, level: CodeMapLevel): Promise<void>;
|
|
25
|
+
declare function onNodeClick(state: MapState, id: string): void;
|
|
26
|
+
declare function levelButtons(root: HTMLElement): HTMLElement[];
|
|
27
|
+
export { draw, levelButtons, load, onNodeClick, refreshHighlight };
|
|
28
|
+
export type { MapState };
|
|
29
|
+
export declare function createState(root: HTMLElement, canvas: SVGSVGElement): MapState;
|
|
30
|
+
export declare function bindState(state: MapState): void;
|
|
31
|
+
//# sourceMappingURL=controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../../../src/client/controller.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE/D,OAAO,EAAwB,KAAK,SAAS,EAAE,MAAM,YAAY,CAAC;AAClE,OAAO,EAAkC,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5E,OAAO,EAA2B,KAAK,SAAS,EAAE,MAAM,eAAe,CAAC;AAExE,KAAK,QAAQ,GAAG;IACd,MAAM,EAAE,aAAa,CAAC;IACtB,IAAI,EAAE,WAAW,GAAG,IAAI,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,KAAK,EAAE,YAAY,CAAC;IACpB,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAClB,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE;QAAC,CAAC,EAAC,MAAM,CAAC;QAAA,CAAC,EAAC,MAAM,CAAA;KAAC,CAAC,CAAC;IAC5C,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,WAAW,CAAC;IAClB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,MAAM,EAAE,WAAW,GAAG,IAAI,CAAC;IAC3B,SAAS,EAAE,SAAS,CAAC;CACtB,CAAC;AA8BF,iBAAS,gBAAgB,CAAC,KAAK,EAAE,QAAQ,QAKxC;AAED,iBAAS,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,QAe5C;AAED,iBAAe,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,YAAY,iBAqBvD;AAYD,iBAAS,WAAW,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,QAY/C;AAED,iBAAS,YAAY,CAAC,IAAI,EAAE,WAAW,GAAG,WAAW,EAAE,CAOtD;AAED,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,gBAAgB,EAAE,CAAC;AACnE,YAAY,EAAE,QAAQ,EAAE,CAAC;AAEzB,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,GAAG,QAAQ,CAO9E;AAED,wBAAgB,SAAS,CAAC,KAAK,EAAE,QAAQ,QAOxC"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { copyFor } from "../shared/copy.js";
|
|
2
|
+
import { layout } from "./layout.js";
|
|
3
|
+
import { buildView, clusterId } from "./model.js";
|
|
4
|
+
import { highlight, render, scaleLabels } from "./render.js";
|
|
5
|
+
import { apply, bindZoomPan, fit } from "./viewport.js";
|
|
6
|
+
function copyOf(state) {
|
|
7
|
+
return copyFor(state.root.getAttribute("data-code-map-lang"));
|
|
8
|
+
}
|
|
9
|
+
function setStatus(state, text) {
|
|
10
|
+
if (state.status)
|
|
11
|
+
state.status.textContent = text;
|
|
12
|
+
}
|
|
13
|
+
function neighbours(state, id) {
|
|
14
|
+
const focus = new Set([id]);
|
|
15
|
+
for (const edge of state.graph?.edges || []) {
|
|
16
|
+
if (edge.source === id)
|
|
17
|
+
focus.add(edge.target);
|
|
18
|
+
if (edge.target === id)
|
|
19
|
+
focus.add(edge.source);
|
|
20
|
+
}
|
|
21
|
+
return focus;
|
|
22
|
+
}
|
|
23
|
+
function filterFocus(state) {
|
|
24
|
+
const query = state.filter.trim().toLowerCase();
|
|
25
|
+
if (!query || !state.data)
|
|
26
|
+
return null;
|
|
27
|
+
const focus = new Set();
|
|
28
|
+
for (const node of state.data.nodes) {
|
|
29
|
+
if (!node.label.toLowerCase().includes(query) && !node.path.toLowerCase().includes(query))
|
|
30
|
+
continue;
|
|
31
|
+
focus.add(state.open.has(node.group) ? node.id : clusterId(node.group));
|
|
32
|
+
}
|
|
33
|
+
return focus;
|
|
34
|
+
}
|
|
35
|
+
function refreshHighlight(state) {
|
|
36
|
+
if (!state.rendered)
|
|
37
|
+
return;
|
|
38
|
+
const focus = state.selected ? neighbours(state, state.selected) : filterFocus(state);
|
|
39
|
+
const members = state.graph ? state.graph.nodes.filter((node) => !node.cluster).length : 0;
|
|
40
|
+
highlight(state.rendered, focus, members <= 60);
|
|
41
|
+
}
|
|
42
|
+
function draw(state, refit) {
|
|
43
|
+
if (!state.data)
|
|
44
|
+
return;
|
|
45
|
+
const graph = buildView(state.data, state.open);
|
|
46
|
+
const box = state.canvas.getBoundingClientRect();
|
|
47
|
+
layout(graph, state.positions, box.width && box.height ? box.height / box.width : 1);
|
|
48
|
+
for (const node of graph.nodes)
|
|
49
|
+
state.positions.set(node.id, { x: node.x || 0, y: node.y || 0 });
|
|
50
|
+
state.graph = graph;
|
|
51
|
+
state.rendered = render(state.canvas, graph);
|
|
52
|
+
if (refit)
|
|
53
|
+
state.transform = fit(state.canvas, graph);
|
|
54
|
+
apply(state.rendered.viewport, state.transform);
|
|
55
|
+
scaleLabels(state.rendered, state.transform.k);
|
|
56
|
+
refreshHighlight(state);
|
|
57
|
+
const copy = copyOf(state);
|
|
58
|
+
const stats = `${state.data.nodes.length} ${copy("nodes")}, ${state.data.edges.length} ${copy("links")}`;
|
|
59
|
+
setStatus(state, state.data.nodes.length ? (state.data.truncated ? `${stats}. ${copy("truncated")}` : stats) : copy("empty"));
|
|
60
|
+
}
|
|
61
|
+
async function load(state, level) {
|
|
62
|
+
state.level = level;
|
|
63
|
+
state.selected = null;
|
|
64
|
+
state.open = new Set();
|
|
65
|
+
setStatus(state, copyOf(state)("loading"));
|
|
66
|
+
const url = String(state.root.getAttribute("data-code-map-url") || "");
|
|
67
|
+
try {
|
|
68
|
+
const response = await fetch(`${url}${url.includes("?") ? "&" : "?"}level=${level}`, { credentials: "same-origin", headers: { Accept: "application/json" } });
|
|
69
|
+
if (!response.ok)
|
|
70
|
+
throw new Error(String(response.status));
|
|
71
|
+
const body = await response.json();
|
|
72
|
+
state.data = (body && body.data) || body;
|
|
73
|
+
if (state.data && state.data.groups.length === 1)
|
|
74
|
+
state.open.add(state.data.groups[0].id);
|
|
75
|
+
draw(state, true);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
state.data = null;
|
|
79
|
+
state.canvas.replaceChildren();
|
|
80
|
+
setStatus(state, copyOf(state)("failed"));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function navigate(state, id) {
|
|
84
|
+
const template = String(state.root.getAttribute("data-code-map-href") || "");
|
|
85
|
+
const node = state.graph?.nodes.find((item) => item.id === id);
|
|
86
|
+
if (!template || !node)
|
|
87
|
+
return;
|
|
88
|
+
const href = template.replace("{path}", encodeURIComponent(node.path)).replace("{line}", String(node.line || 1));
|
|
89
|
+
const detail = { href, line: node.line, path: node.path };
|
|
90
|
+
const event = new CustomEvent("code-map:open", { bubbles: true, cancelable: true, detail });
|
|
91
|
+
if (state.root.dispatchEvent(event))
|
|
92
|
+
window.location.assign(href);
|
|
93
|
+
}
|
|
94
|
+
function onNodeClick(state, id) {
|
|
95
|
+
const node = state.graph?.nodes.find((item) => item.id === id);
|
|
96
|
+
if (!node)
|
|
97
|
+
return;
|
|
98
|
+
if (node.cluster) {
|
|
99
|
+
state.open.add(node.group);
|
|
100
|
+
state.selected = null;
|
|
101
|
+
draw(state, true);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
if (state.selected === id)
|
|
105
|
+
return navigate(state, id);
|
|
106
|
+
state.selected = id;
|
|
107
|
+
refreshHighlight(state);
|
|
108
|
+
}
|
|
109
|
+
function levelButtons(root) {
|
|
110
|
+
let scope = root.parentElement;
|
|
111
|
+
for (let depth = 0; scope && depth < 8; depth += 1, scope = scope.parentElement) {
|
|
112
|
+
const found = Array.from(scope.querySelectorAll("[data-code-map-switch]"));
|
|
113
|
+
if (found.length)
|
|
114
|
+
return found;
|
|
115
|
+
}
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
export { draw, levelButtons, load, onNodeClick, refreshHighlight };
|
|
119
|
+
export function createState(root, canvas) {
|
|
120
|
+
return {
|
|
121
|
+
canvas, data: null, filter: "", graph: null,
|
|
122
|
+
level: root.getAttribute("data-code-map-level") === "function" ? "function" : "file",
|
|
123
|
+
open: new Set(), positions: new Map(), rendered: null, root, selected: null,
|
|
124
|
+
status: root.querySelector("[data-code-map-status]"), transform: { k: 1, x: 0, y: 0 },
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export function bindState(state) {
|
|
128
|
+
bindZoomPan(state.canvas, () => state.transform, (next) => {
|
|
129
|
+
state.transform = next;
|
|
130
|
+
if (!state.rendered)
|
|
131
|
+
return;
|
|
132
|
+
apply(state.rendered.viewport, next);
|
|
133
|
+
scaleLabels(state.rendered, next.k);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.js","sourceRoot":"","sources":["../../../src/client/controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAkCA,iBAAS,WAAW,CAAC,IAAI,EAAE,WAAW,QAUrC;AAED,iBAAS,YAAY,CAAC,KAAK,GAAE,UAAqB,QAEjD;AAED,iBAAS,cAAc,CAAC,KAAK,GAAE,UAAqB,QAMnD;AAED,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { bindState, createState, levelButtons, load, onNodeClick, refreshHighlight } from "./controller.js";
|
|
2
|
+
const bound = new WeakMap();
|
|
3
|
+
function bindClicks(state) {
|
|
4
|
+
let downAt = null;
|
|
5
|
+
state.canvas.addEventListener("pointerdown", (event) => { downAt = { x: event.clientX, y: event.clientY }; });
|
|
6
|
+
state.canvas.addEventListener("click", (event) => {
|
|
7
|
+
const moved = downAt && Math.hypot(event.clientX - downAt.x, event.clientY - downAt.y) > 4;
|
|
8
|
+
if (moved)
|
|
9
|
+
return;
|
|
10
|
+
const node = event.target.closest("[data-code-map-node]");
|
|
11
|
+
if (node)
|
|
12
|
+
return onNodeClick(state, String(node.getAttribute("data-code-map-node")));
|
|
13
|
+
state.selected = null;
|
|
14
|
+
refreshHighlight(state);
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
function bindControls(state) {
|
|
18
|
+
const filter = state.root.querySelector("[data-code-map-filter]");
|
|
19
|
+
filter?.addEventListener("input", () => {
|
|
20
|
+
state.filter = filter.value;
|
|
21
|
+
state.selected = null;
|
|
22
|
+
refreshHighlight(state);
|
|
23
|
+
});
|
|
24
|
+
const buttons = levelButtons(state.root);
|
|
25
|
+
for (const button of buttons) {
|
|
26
|
+
button.addEventListener("click", () => {
|
|
27
|
+
const level = button.getAttribute("data-code-map-switch") === "function" ? "function" : "file";
|
|
28
|
+
buttons.forEach((item) => item.setAttribute("aria-pressed", item === button ? "true" : "false"));
|
|
29
|
+
void load(state, level);
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function bindCodeMap(root) {
|
|
34
|
+
if (bound.has(root))
|
|
35
|
+
return;
|
|
36
|
+
const canvas = root.querySelector("svg[data-code-map-canvas]");
|
|
37
|
+
if (!canvas)
|
|
38
|
+
return;
|
|
39
|
+
const state = createState(root, canvas);
|
|
40
|
+
bound.set(root, state);
|
|
41
|
+
bindState(state);
|
|
42
|
+
bindClicks(state);
|
|
43
|
+
bindControls(state);
|
|
44
|
+
void load(state, state.level);
|
|
45
|
+
}
|
|
46
|
+
function bindCodeMaps(scope = document) {
|
|
47
|
+
scope.querySelectorAll("[data-code-map-root]").forEach(bindCodeMap);
|
|
48
|
+
}
|
|
49
|
+
function reloadCodeMaps(scope = document) {
|
|
50
|
+
scope.querySelectorAll("[data-code-map-root]").forEach((root) => {
|
|
51
|
+
const state = bound.get(root);
|
|
52
|
+
if (state)
|
|
53
|
+
void load(state, state.level);
|
|
54
|
+
else
|
|
55
|
+
bindCodeMap(root);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
export { bindCodeMap, bindCodeMaps, reloadCodeMaps };
|
|
59
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { ViewGraph, ViewNode } from "./model.js";
|
|
2
|
+
declare function radius(node: ViewNode): number;
|
|
3
|
+
declare function layout(graph: ViewGraph, previous: Map<string, {
|
|
4
|
+
x: number;
|
|
5
|
+
y: number;
|
|
6
|
+
}>, aspect?: number): void;
|
|
7
|
+
export { layout, radius };
|
|
8
|
+
//# sourceMappingURL=layout.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../src/client/layout.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtD,iBAAS,MAAM,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAEtC;AAYD,iBAAS,MAAM,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE;IAAC,CAAC,EAAC,MAAM,CAAC;IAAA,CAAC,EAAC,MAAM,CAAA;CAAC,CAAC,EAAE,MAAM,SAAI,GAAG,IAAI,CAgB9F;AAED,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { forceCenter, forceCollide, forceLink, forceManyBody, forceSimulation, forceX, forceY } from "d3-force";
|
|
2
|
+
function radius(node) {
|
|
3
|
+
return node.cluster ? 10 + Math.sqrt(node.count) * 2.4 : 4 + Math.min(10, Math.sqrt(node.size) / 2);
|
|
4
|
+
}
|
|
5
|
+
function seed(graph, previous) {
|
|
6
|
+
graph.nodes.forEach((node, index) => {
|
|
7
|
+
const known = previous.get(node.id) || previous.get(`group:${node.group}`);
|
|
8
|
+
const angle = index * 2.399963;
|
|
9
|
+
const spread = known ? 18 : 40 + Math.sqrt(index) * 30;
|
|
10
|
+
node.x = (known ? known.x : 0) + Math.cos(angle) * spread;
|
|
11
|
+
node.y = (known ? known.y : 0) + Math.sin(angle) * spread;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
function layout(graph, previous, aspect = 1) {
|
|
15
|
+
seed(graph, previous);
|
|
16
|
+
const links = graph.edges.map((edge) => ({ ...edge }));
|
|
17
|
+
const simulation = forceSimulation(graph.nodes)
|
|
18
|
+
.force("link", forceLink(links).id((node) => node.id).distance((link) => 56 + radius(link.source) + radius(link.target)).strength(0.2))
|
|
19
|
+
.force("charge", forceManyBody().strength((node) => (node.cluster ? -320 : -150)))
|
|
20
|
+
.force("collide", forceCollide((node) => radius(node) + (node.cluster ? 26 : 22)).iterations(2))
|
|
21
|
+
.force("x", forceX(0).strength(0.04 * Math.max(1, aspect)))
|
|
22
|
+
.force("y", forceY(0).strength(0.04 / Math.max(1, 1 / aspect)))
|
|
23
|
+
.force("center", forceCenter(0, 0))
|
|
24
|
+
.stop();
|
|
25
|
+
const ticks = graph.nodes.length > 600 ? 160 : 300;
|
|
26
|
+
for (let tick = 0; tick < ticks; tick += 1)
|
|
27
|
+
simulation.tick();
|
|
28
|
+
}
|
|
29
|
+
export { layout, radius };
|
|
30
|
+
//# sourceMappingURL=layout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"layout.js","sourceRoot":"","sources":["../../../src/client/layout.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { CodeMapData } from "../shared/types.d.ts";
|
|
2
|
+
type ViewNode = {
|
|
3
|
+
cluster: boolean;
|
|
4
|
+
count: number;
|
|
5
|
+
group: string;
|
|
6
|
+
id: string;
|
|
7
|
+
label: string;
|
|
8
|
+
line: number | null;
|
|
9
|
+
path: string;
|
|
10
|
+
size: number;
|
|
11
|
+
x?: number;
|
|
12
|
+
y?: number;
|
|
13
|
+
};
|
|
14
|
+
type ViewEdge = {
|
|
15
|
+
source: string;
|
|
16
|
+
target: string;
|
|
17
|
+
weight: number;
|
|
18
|
+
};
|
|
19
|
+
type ViewGraph = {
|
|
20
|
+
edges: ViewEdge[];
|
|
21
|
+
nodes: ViewNode[];
|
|
22
|
+
};
|
|
23
|
+
declare function clusterId(group: string): string;
|
|
24
|
+
declare function buildView(data: CodeMapData, open: Set<string>): ViewGraph;
|
|
25
|
+
export { buildView, clusterId };
|
|
26
|
+
export type { ViewEdge, ViewGraph, ViewNode };
|
|
27
|
+
//# sourceMappingURL=model.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../../src/client/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAe,MAAM,eAAe,CAAC;AAE9D,KAAK,QAAQ,GAAG;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;CACZ,CAAC;AAEF,KAAK,QAAQ,GAAG;IACd,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,KAAK,SAAS,GAAG;IACf,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,KAAK,EAAE,QAAQ,EAAE,CAAC;CACnB,CAAC;AAIF,iBAAS,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAExC;AA0BD,iBAAS,SAAS,CAAC,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,SAAS,CA4BlE;AAED,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;AAChC,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const MAX_OPEN_GROUP_NODES = 400;
|
|
2
|
+
function clusterId(group) {
|
|
3
|
+
return `group:${group}`;
|
|
4
|
+
}
|
|
5
|
+
function clusterNode(group) {
|
|
6
|
+
const id = clusterId(group.id);
|
|
7
|
+
return { cluster: true, count: group.size, group: group.id, id, label: group.label, line: null, path: group.id, size: group.size };
|
|
8
|
+
}
|
|
9
|
+
function memberNode(node) {
|
|
10
|
+
return { cluster: false, count: 1, group: node.group, id: node.id, label: node.label, line: node.line, path: node.path, size: node.size };
|
|
11
|
+
}
|
|
12
|
+
function degreeOf(data) {
|
|
13
|
+
const degree = new Map();
|
|
14
|
+
for (const edge of data.edges) {
|
|
15
|
+
degree.set(edge.source, (degree.get(edge.source) || 0) + 1);
|
|
16
|
+
degree.set(edge.target, (degree.get(edge.target) || 0) + 1);
|
|
17
|
+
}
|
|
18
|
+
return degree;
|
|
19
|
+
}
|
|
20
|
+
function openMembers(data, group, degree) {
|
|
21
|
+
const members = data.nodes.filter((node) => node.group === group);
|
|
22
|
+
if (members.length <= MAX_OPEN_GROUP_NODES)
|
|
23
|
+
return members;
|
|
24
|
+
return members.sort((left, right) => (degree.get(right.id) || 0) - (degree.get(left.id) || 0)).slice(0, MAX_OPEN_GROUP_NODES);
|
|
25
|
+
}
|
|
26
|
+
function buildView(data, open) {
|
|
27
|
+
const degree = degreeOf(data);
|
|
28
|
+
const visible = new Map();
|
|
29
|
+
const nodes = [];
|
|
30
|
+
for (const group of data.groups) {
|
|
31
|
+
if (!open.has(group.id)) {
|
|
32
|
+
nodes.push(clusterNode(group));
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
for (const member of openMembers(data, group.id, degree)) {
|
|
36
|
+
nodes.push(memberNode(member));
|
|
37
|
+
visible.set(member.id, member.id);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const owner = new Map(data.nodes.map((node) => [node.id, visible.get(node.id) || (open.has(node.group) ? "" : clusterId(node.group))]));
|
|
41
|
+
const weights = new Map();
|
|
42
|
+
for (const edge of data.edges) {
|
|
43
|
+
const source = owner.get(edge.source);
|
|
44
|
+
const target = owner.get(edge.target);
|
|
45
|
+
if (!source || !target || source === target)
|
|
46
|
+
continue;
|
|
47
|
+
const key = `${source}\u0000${target}`;
|
|
48
|
+
weights.set(key, (weights.get(key) || 0) + edge.weight);
|
|
49
|
+
}
|
|
50
|
+
const edges = [...weights.entries()].map(([key, weight]) => {
|
|
51
|
+
const [source, target] = key.split("\u0000");
|
|
52
|
+
return { source, target, weight };
|
|
53
|
+
});
|
|
54
|
+
return { edges, nodes };
|
|
55
|
+
}
|
|
56
|
+
export { buildView, clusterId };
|
|
57
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../../src/client/model.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ViewGraph, ViewNode } from "./model.js";
|
|
2
|
+
type Rendered = {
|
|
3
|
+
edges: {
|
|
4
|
+
element: SVGLineElement;
|
|
5
|
+
source: string;
|
|
6
|
+
target: string;
|
|
7
|
+
}[];
|
|
8
|
+
nodes: Map<string, {
|
|
9
|
+
element: SVGGElement;
|
|
10
|
+
label: SVGTextElement;
|
|
11
|
+
node: ViewNode;
|
|
12
|
+
}>;
|
|
13
|
+
viewport: SVGGElement;
|
|
14
|
+
};
|
|
15
|
+
declare function render(canvas: SVGSVGElement, graph: ViewGraph): Rendered;
|
|
16
|
+
declare function highlight(rendered: Rendered, focus: Set<string> | null, labelAll: boolean): void;
|
|
17
|
+
declare function scaleLabels(rendered: Rendered, zoom: number): void;
|
|
18
|
+
export { highlight, render, scaleLabels };
|
|
19
|
+
export type { Rendered };
|
|
20
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../src/client/render.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAItD,KAAK,QAAQ,GAAG;IACd,KAAK,EAAE;QAAE,OAAO,EAAE,cAAc,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IACrE,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE;QAAC,OAAO,EAAC,WAAW,CAAC;QAAA,KAAK,EAAC,cAAc,CAAC;QAAA,IAAI,EAAC,QAAQ,CAAA;KAAC,CAAC,CAAC;IAC7E,QAAQ,EAAE,WAAW,CAAC;CACvB,CAAC;AA0DF,iBAAS,MAAM,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,SAAS,GAAG,QAAQ,CAkBjE;AAED,iBAAS,SAAS,CAAC,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,GAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,QAUhF;AAED,iBAAS,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,QAMpD;AAED,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;AAC1C,YAAY,EAAE,QAAQ,EAAE,CAAC"}
|