@nanonets/graft 0.4.5 → 0.5.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/README.md +58 -12
- package/dist/ai/synthesize.d.ts.map +1 -1
- package/dist/ai/synthesize.js +1 -0
- package/dist/ai/synthesize.js.map +1 -1
- package/dist/ask/ask.d.ts +33 -0
- package/dist/ask/ask.d.ts.map +1 -1
- package/dist/ask/ask.js +105 -7
- package/dist/ask/ask.js.map +1 -1
- package/dist/ask/graphrank.d.ts.map +1 -1
- package/dist/ask/graphrank.js +1 -13
- package/dist/ask/graphrank.js.map +1 -1
- package/dist/claude/format.d.ts +17 -0
- package/dist/claude/format.d.ts.map +1 -1
- package/dist/claude/format.js +40 -1
- package/dist/claude/format.js.map +1 -1
- package/dist/claude/hooks.d.ts.map +1 -1
- package/dist/claude/hooks.js +16 -15
- package/dist/claude/hooks.js.map +1 -1
- package/dist/claude/skill-template.d.ts.map +1 -1
- package/dist/claude/skill-template.js +15 -5
- package/dist/claude/skill-template.js.map +1 -1
- package/dist/claude/state.d.ts +4 -0
- package/dist/claude/state.d.ts.map +1 -1
- package/dist/claude/state.js +1 -1
- package/dist/claude/state.js.map +1 -1
- package/dist/cli.d.ts +2 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +75 -2
- package/dist/cli.js.map +1 -1
- package/dist/engine.d.ts +1 -0
- package/dist/engine.d.ts.map +1 -1
- package/dist/engine.js +1 -1
- package/dist/engine.js.map +1 -1
- package/dist/graph/bindings.d.ts +42 -0
- package/dist/graph/bindings.d.ts.map +1 -0
- package/dist/graph/bindings.js +304 -0
- package/dist/graph/bindings.js.map +1 -0
- package/dist/graph/extract.d.ts +17 -1
- package/dist/graph/extract.d.ts.map +1 -1
- package/dist/graph/extract.js +47 -5
- package/dist/graph/extract.js.map +1 -1
- package/dist/graph/map.d.ts +71 -0
- package/dist/graph/map.d.ts.map +1 -0
- package/dist/graph/map.js +150 -0
- package/dist/graph/map.js.map +1 -0
- package/dist/graph/relations.d.ts +14 -0
- package/dist/graph/relations.d.ts.map +1 -0
- package/dist/graph/relations.js +8 -0
- package/dist/graph/relations.js.map +1 -0
- package/dist/graph/resolve.d.ts.map +1 -1
- package/dist/graph/resolve.js +0 -0
- package/dist/graph/resolve.js.map +1 -1
- package/dist/graph/traverse.d.ts.map +1 -1
- package/dist/graph/traverse.js +1 -12
- package/dist/graph/traverse.js.map +1 -1
- package/dist/hosts/instructions.d.ts.map +1 -1
- package/dist/hosts/instructions.js +13 -6
- package/dist/hosts/instructions.js.map +1 -1
- package/dist/mcp/server.d.ts +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +2 -2
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +1 -1
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +80 -7
- package/dist/mcp/tools.js.map +1 -1
- package/dist/search/grep-cli.d.ts +32 -0
- package/dist/search/grep-cli.d.ts.map +1 -0
- package/dist/search/grep-cli.js +101 -0
- package/dist/search/grep-cli.js.map +1 -0
- package/dist/search/grep.d.ts +55 -0
- package/dist/search/grep.d.ts.map +1 -0
- package/dist/search/grep.js +126 -0
- package/dist/search/grep.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grep-cli.d.ts","sourceRoot":"","sources":["../../src/search/grep-cli.ts"],"names":[],"mappings":"AAYA,OAAO,EAA6B,KAAK,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvE,MAAM,WAAW,cAAc;IAC7B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAaD,oFAAoF;AACpF,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAG3D;AAYD;gEACgE;AAChE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAM3D;AAED;;;;;;;iEAOiE;AACjE,wBAAgB,WAAW,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAKtD;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CA6BvF"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CLI wiring + human formatter for `graft grep`.
|
|
3
|
+
*
|
|
4
|
+
* Kept out of cli.ts (argument wiring only) and out of grep.ts (pure core,
|
|
5
|
+
* unit-testable against hand-built fixture graphs without touching a real
|
|
6
|
+
* repo root) — same split as traverse.ts/traverse-cli.ts. `formatGrepResult`
|
|
7
|
+
* is exported so `graft_grep` in `src/mcp/tools.ts` renders the identical
|
|
8
|
+
* report, rather than re-implementing it.
|
|
9
|
+
*/
|
|
10
|
+
import { resolve } from "node:path";
|
|
11
|
+
import { contextDirFor } from "../context/node-file.js";
|
|
12
|
+
import { loadGraphCached } from "../graph/load.js";
|
|
13
|
+
import { grepGraph } from "./grep.js";
|
|
14
|
+
function groupHeader(g) {
|
|
15
|
+
if (g.symbol)
|
|
16
|
+
return `${g.symbol.name} · ${g.symbol.kind} · ${g.symbol.path}:${g.symbol.span} · ${g.inDegree} in-edges`;
|
|
17
|
+
return `${g.path} (module level) · ${g.inDegree} in-edges`;
|
|
18
|
+
}
|
|
19
|
+
function formatGroup(g) {
|
|
20
|
+
const lines = [groupHeader(g)];
|
|
21
|
+
for (const h of g.hits)
|
|
22
|
+
lines.push(` L${h.line}: ${h.text}`);
|
|
23
|
+
return lines.join("\n");
|
|
24
|
+
}
|
|
25
|
+
/** `"<pattern>" — N hits in M symbols across K files (searched T indexed files)` */
|
|
26
|
+
export function formatGrepHeader(result) {
|
|
27
|
+
const filesHit = new Set(result.groups.map((g) => g.path)).size;
|
|
28
|
+
return `"${result.pattern}" — ${result.totalHits} hits in ${result.groups.length} symbols across ${filesHit} files (searched ${result.filesSearched} indexed files)`;
|
|
29
|
+
}
|
|
30
|
+
/** Loud truncation note — dropped counts are never silent. */
|
|
31
|
+
function truncationNote(result) {
|
|
32
|
+
const { files, hits } = result.truncated;
|
|
33
|
+
if (files === 0 && hits === 0)
|
|
34
|
+
return null;
|
|
35
|
+
const parts = [];
|
|
36
|
+
if (hits > 0)
|
|
37
|
+
parts.push(`${hits} more hit${hits === 1 ? "" : "s"} beyond the cap`);
|
|
38
|
+
if (files > 0)
|
|
39
|
+
parts.push(`${files} indexed file${files === 1 ? "" : "s"} unreadable`);
|
|
40
|
+
return `(truncated: ${parts.join(", ")} — narrow with --in or refine the pattern)`;
|
|
41
|
+
}
|
|
42
|
+
/** Full human report: header, blank line, then one block per group (header +
|
|
43
|
+
* indented hit lines), each block separated by a blank line. */
|
|
44
|
+
export function formatGrepResult(result) {
|
|
45
|
+
const blocks = [formatGrepHeader(result), "", ...result.groups.map((g) => formatGroup(g) + "\n")];
|
|
46
|
+
let out = blocks.join("\n").replace(/\n+$/, "\n");
|
|
47
|
+
const note = truncationNote(result);
|
|
48
|
+
if (note)
|
|
49
|
+
out += note + "\n";
|
|
50
|
+
return out;
|
|
51
|
+
}
|
|
52
|
+
/** Loud, actionable zero-hit note (never a bare empty result) — printed to
|
|
53
|
+
* stderr; the caller still exits 0, since "no hits in the indexed graph" is
|
|
54
|
+
* not an error, just a reason to fall back to a real grep.
|
|
55
|
+
*
|
|
56
|
+
* Truncation is never silent, even on the zero-hit path: if some indexed
|
|
57
|
+
* files couldn't be read (`truncated.files > 0`), that's called out too —
|
|
58
|
+
* otherwise a zero-hit result on a stale graph or wrong root reads as "no
|
|
59
|
+
* matches" when really some files were never searched at all. */
|
|
60
|
+
export function zeroHitNote(result) {
|
|
61
|
+
const base = `no hits for "${result.pattern}" in ${result.filesSearched} indexed files — unindexed files (docs, configs, new files) aren't searched; try grep -rn "${result.pattern}" for those`;
|
|
62
|
+
const { files } = result.truncated;
|
|
63
|
+
if (files === 0)
|
|
64
|
+
return base;
|
|
65
|
+
return `${base} — note: ${files} indexed file${files === 1 ? "" : "s"} could not be read (stale graph? run graft build)`;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Resolve the graph at `dir` (respecting `--dir`), run `grepGraph`, and print
|
|
69
|
+
* either the human report or `--json`. Exits the process (code 1) when
|
|
70
|
+
* there's no graph at all or the pattern fails to compile as a regex — both
|
|
71
|
+
* are caller-facing mistakes, not recoverable states. Zero hits is NOT an
|
|
72
|
+
* error: it prints a loud note to stderr and exits 0.
|
|
73
|
+
*/
|
|
74
|
+
export function runGrepCommand(pattern, dir, opts) {
|
|
75
|
+
const root = resolve(dir);
|
|
76
|
+
const contextDir = contextDirFor(root, opts.globalDir);
|
|
77
|
+
const graph = loadGraphCached(contextDir);
|
|
78
|
+
if (!graph) {
|
|
79
|
+
console.error("✗ no graph — run graft build first");
|
|
80
|
+
process.exit(1);
|
|
81
|
+
}
|
|
82
|
+
let result;
|
|
83
|
+
try {
|
|
84
|
+
result = grepGraph(graph, root, pattern, { ignoreCase: opts.ignoreCase, fixed: opts.fixed, in: opts.in });
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
console.error(`✗ invalid pattern "${pattern}": ${err instanceof Error ? err.message : String(err)}`);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
if (opts.json) {
|
|
92
|
+
console.log(JSON.stringify(result, null, 2));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (result.totalHits === 0) {
|
|
96
|
+
console.error(zeroHitNote(result));
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
process.stdout.write(formatGrepResult(result));
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=grep-cli.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grep-cli.js","sourceRoot":"","sources":["../../src/search/grep-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { GraphV1 } from "../graph/types.js";
|
|
2
|
+
export interface GrepHit {
|
|
3
|
+
line: number;
|
|
4
|
+
/** Trimmed line text, capped at 160 chars. */
|
|
5
|
+
text: string;
|
|
6
|
+
}
|
|
7
|
+
export interface GrepSymbolRef {
|
|
8
|
+
id: string;
|
|
9
|
+
/** Qualified scope-joined name (e.g. `FastAPI.include_router`), not just
|
|
10
|
+
* the bare symbol name — the id's segment after the file-path `#`. */
|
|
11
|
+
name: string;
|
|
12
|
+
kind: string;
|
|
13
|
+
path: string;
|
|
14
|
+
span: string;
|
|
15
|
+
}
|
|
16
|
+
export interface GrepGroup {
|
|
17
|
+
/** null → file-level: the hit lies outside every indexed symbol's span
|
|
18
|
+
* (module-level code — imports, top-level statements, module constants). */
|
|
19
|
+
symbol: GrepSymbolRef | null;
|
|
20
|
+
path: string;
|
|
21
|
+
/** Incoming WALK_RELATIONS edges targeting the symbol — always 0 for
|
|
22
|
+
* file-level groups (there's no single symbol id to count edges against). */
|
|
23
|
+
inDegree: number;
|
|
24
|
+
hits: GrepHit[];
|
|
25
|
+
}
|
|
26
|
+
export interface GrepResult {
|
|
27
|
+
pattern: string;
|
|
28
|
+
/** Indexed file nodes considered (after the `in` filter), whether or not
|
|
29
|
+
* each was actually readable — matches the CLI's "searched N indexed
|
|
30
|
+
* files" wording. */
|
|
31
|
+
filesSearched: number;
|
|
32
|
+
/** Hits actually collected (<= maxHits). */
|
|
33
|
+
totalHits: number;
|
|
34
|
+
/** Sorted: inDegree desc, then path asc. */
|
|
35
|
+
groups: GrepGroup[];
|
|
36
|
+
/** Dropped counts — never silent. `files`: indexed file nodes that
|
|
37
|
+
* couldn't be read from disk. `hits`: matches found beyond `maxHits`,
|
|
38
|
+
* counted but not collected. */
|
|
39
|
+
truncated: {
|
|
40
|
+
files: number;
|
|
41
|
+
hits: number;
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
export interface GrepOptions {
|
|
45
|
+
ignoreCase?: boolean;
|
|
46
|
+
/** Treat `pattern` as a literal string (regex-escaped), not a regex. */
|
|
47
|
+
fixed?: boolean;
|
|
48
|
+
/** Narrow to file nodes whose path contains this substring. */
|
|
49
|
+
in?: string;
|
|
50
|
+
/** Stop collecting hits after this many; the rest are tallied into
|
|
51
|
+
* `truncated.hits`. Default 300. */
|
|
52
|
+
maxHits?: number;
|
|
53
|
+
}
|
|
54
|
+
export declare function grepGraph(graph: GraphV1, repoRoot: string, pattern: string, opts?: GrepOptions): GrepResult;
|
|
55
|
+
//# sourceMappingURL=grep.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grep.d.ts","sourceRoot":"","sources":["../../src/search/grep.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,OAAO,EAAU,MAAM,mBAAmB,CAAC;AAGzD,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX;0EACsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB;gFAC4E;IAC5E,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb;iFAC6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,OAAO,EAAE,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB;;yBAEqB;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB;;oCAEgC;IAChC,SAAS,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;CAC5C;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,+DAA+D;IAC/D,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ;wCACoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAgED,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,WAAgB,GAAG,UAAU,CA8D/G"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `graft grep` core: regex search over the graph's indexed files, with hits
|
|
3
|
+
* grouped by their innermost enclosing symbol and ranked by incoming-edge
|
|
4
|
+
* count (coupling) — a grep that answers "which of these hits matters",
|
|
5
|
+
* because plain `grep -rn` gives no way to tell a hit inside a
|
|
6
|
+
* heavily-depended-on function from one inside dead code.
|
|
7
|
+
*
|
|
8
|
+
* Pure I/O + regex, no CLI/MCP concerns: `grep-cli.ts` formats this into
|
|
9
|
+
* human text and wires the CLI command; `mcp/tools.ts` renders the same
|
|
10
|
+
* shape for the `graft_grep` tool.
|
|
11
|
+
*/
|
|
12
|
+
import { readFileSync } from "node:fs";
|
|
13
|
+
import { join } from "node:path";
|
|
14
|
+
import { WALK_RELATIONS } from "../graph/relations.js";
|
|
15
|
+
const DEFAULT_MAX_HITS = 300;
|
|
16
|
+
const MAX_HIT_TEXT = 160;
|
|
17
|
+
const SPAN_RE = /^L(\d+)-L(\d+)$/;
|
|
18
|
+
function escapeRegExp(s) {
|
|
19
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
20
|
+
}
|
|
21
|
+
function spanBounds(span) {
|
|
22
|
+
const m = SPAN_RE.exec(span);
|
|
23
|
+
if (!m)
|
|
24
|
+
return null;
|
|
25
|
+
return { start: Number(m[1]), end: Number(m[2]) };
|
|
26
|
+
}
|
|
27
|
+
/** The file's symbol nodes, sorted ascending by span start — the order
|
|
28
|
+
* `enclosingSymbol` scans in to find the innermost containing span. */
|
|
29
|
+
function symbolsOf(graph, path) {
|
|
30
|
+
const out = [];
|
|
31
|
+
for (const n of graph.nodes) {
|
|
32
|
+
if (n.kind === "file" || n.path !== path)
|
|
33
|
+
continue;
|
|
34
|
+
const b = spanBounds(n.span);
|
|
35
|
+
if (b)
|
|
36
|
+
out.push({ node: n, start: b.start, end: b.end });
|
|
37
|
+
}
|
|
38
|
+
out.sort((a, b) => a.start - b.start);
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
/** Innermost symbol containing `line`: among spans that contain it, the one
|
|
42
|
+
* with the greatest start line. Symbols are pre-sorted ascending by start,
|
|
43
|
+
* so the last containing match seen wins, and the scan can stop as soon as
|
|
44
|
+
* a span starts after `line` — nothing later in the sort can contain it. */
|
|
45
|
+
function enclosingSymbol(symbols, line) {
|
|
46
|
+
let found = null;
|
|
47
|
+
for (const s of symbols) {
|
|
48
|
+
if (s.start > line)
|
|
49
|
+
break;
|
|
50
|
+
if (line <= s.end)
|
|
51
|
+
found = s.node;
|
|
52
|
+
}
|
|
53
|
+
return found;
|
|
54
|
+
}
|
|
55
|
+
/** Incoming WALK_RELATIONS edge count per target id — one pass over
|
|
56
|
+
* `graph.edges`, computed once per call and shared across every hit. */
|
|
57
|
+
function computeInDegree(graph) {
|
|
58
|
+
const deg = new Map();
|
|
59
|
+
for (const e of graph.edges) {
|
|
60
|
+
if (!WALK_RELATIONS.has(e.relation))
|
|
61
|
+
continue;
|
|
62
|
+
deg.set(e.target, (deg.get(e.target) ?? 0) + 1);
|
|
63
|
+
}
|
|
64
|
+
return deg;
|
|
65
|
+
}
|
|
66
|
+
function toSymbolRef(n) {
|
|
67
|
+
const hash = n.id.indexOf("#");
|
|
68
|
+
return { id: n.id, name: hash >= 0 ? n.id.slice(hash + 1) : n.name, kind: n.kind, path: n.path, span: n.span };
|
|
69
|
+
}
|
|
70
|
+
export function grepGraph(graph, repoRoot, pattern, opts = {}) {
|
|
71
|
+
const maxHits = opts.maxHits ?? DEFAULT_MAX_HITS;
|
|
72
|
+
const source = opts.fixed ? escapeRegExp(pattern) : pattern;
|
|
73
|
+
const regex = new RegExp(source, opts.ignoreCase ? "i" : "");
|
|
74
|
+
const inDegree = computeInDegree(graph);
|
|
75
|
+
const fileNodes = graph.nodes.filter((n) => n.kind === "file" && (!opts.in || n.path.includes(opts.in)));
|
|
76
|
+
const groups = new Map();
|
|
77
|
+
let collected = 0;
|
|
78
|
+
let truncatedHits = 0;
|
|
79
|
+
let truncatedFiles = 0;
|
|
80
|
+
for (const file of fileNodes) {
|
|
81
|
+
let text;
|
|
82
|
+
try {
|
|
83
|
+
text = readFileSync(join(repoRoot, file.path), "utf8");
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
truncatedFiles++;
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
const symbols = symbolsOf(graph, file.path);
|
|
90
|
+
const lines = text.split("\n");
|
|
91
|
+
for (let i = 0; i < lines.length; i++) {
|
|
92
|
+
const raw = lines[i];
|
|
93
|
+
if (!regex.test(raw))
|
|
94
|
+
continue;
|
|
95
|
+
if (collected >= maxHits) {
|
|
96
|
+
truncatedHits++;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
collected++;
|
|
100
|
+
const lineNo = i + 1;
|
|
101
|
+
const sym = enclosingSymbol(symbols, lineNo);
|
|
102
|
+
const key = sym ? sym.id : `file:${file.path}`;
|
|
103
|
+
let group = groups.get(key);
|
|
104
|
+
if (!group) {
|
|
105
|
+
group = {
|
|
106
|
+
symbol: sym ? toSymbolRef(sym) : null,
|
|
107
|
+
path: file.path,
|
|
108
|
+
inDegree: sym ? (inDegree.get(sym.id) ?? 0) : 0,
|
|
109
|
+
hits: [],
|
|
110
|
+
};
|
|
111
|
+
groups.set(key, group);
|
|
112
|
+
}
|
|
113
|
+
const trimmed = raw.trim();
|
|
114
|
+
group.hits.push({ line: lineNo, text: trimmed.length > MAX_HIT_TEXT ? trimmed.slice(0, MAX_HIT_TEXT) : trimmed });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
const sortedGroups = [...groups.values()].sort((a, b) => b.inDegree - a.inDegree || a.path.localeCompare(b.path));
|
|
118
|
+
return {
|
|
119
|
+
pattern,
|
|
120
|
+
filesSearched: fileNodes.length,
|
|
121
|
+
totalHits: collected,
|
|
122
|
+
groups: sortedGroups,
|
|
123
|
+
truncated: { files: truncatedFiles, hits: truncatedHits },
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=grep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grep.js","sourceRoot":"","sources":["../../src/search/grep.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED