memorydetective 1.0.1 → 1.2.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.
Files changed (52) hide show
  1. package/CHANGELOG.md +48 -1
  2. package/LICENSE +201 -21
  3. package/NOTICE +19 -0
  4. package/README.md +22 -23
  5. package/dist/cli.js +49 -5
  6. package/dist/cli.js.map +1 -1
  7. package/dist/index.js +52 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/parsers/shortenClassName.d.ts +45 -0
  10. package/dist/parsers/shortenClassName.js +155 -0
  11. package/dist/parsers/shortenClassName.js.map +1 -0
  12. package/dist/runtime/sourcekit/client.d.ts +37 -0
  13. package/dist/runtime/sourcekit/client.js +132 -0
  14. package/dist/runtime/sourcekit/client.js.map +1 -0
  15. package/dist/runtime/sourcekit/pool.d.ts +25 -0
  16. package/dist/runtime/sourcekit/pool.js +101 -0
  17. package/dist/runtime/sourcekit/pool.js.map +1 -0
  18. package/dist/runtime/sourcekit/protocol.d.ts +37 -0
  19. package/dist/runtime/sourcekit/protocol.js +161 -0
  20. package/dist/runtime/sourcekit/protocol.js.map +1 -0
  21. package/dist/tools/analyzeMemgraph.d.ts +11 -2
  22. package/dist/tools/analyzeMemgraph.js +37 -9
  23. package/dist/tools/analyzeMemgraph.js.map +1 -1
  24. package/dist/tools/findCycles.d.ts +6 -2
  25. package/dist/tools/findCycles.js +11 -6
  26. package/dist/tools/findCycles.js.map +1 -1
  27. package/dist/tools/reachableFromCycle.d.ts +61 -0
  28. package/dist/tools/reachableFromCycle.js +116 -0
  29. package/dist/tools/reachableFromCycle.js.map +1 -0
  30. package/dist/tools/renderCycleGraph.d.ts +1 -1
  31. package/dist/tools/swift/_helpers.d.ts +29 -0
  32. package/dist/tools/swift/_helpers.js +64 -0
  33. package/dist/tools/swift/_helpers.js.map +1 -0
  34. package/dist/tools/swift/findSymbolReferences.d.ts +30 -0
  35. package/dist/tools/swift/findSymbolReferences.js +56 -0
  36. package/dist/tools/swift/findSymbolReferences.js.map +1 -0
  37. package/dist/tools/swift/getHoverInfo.d.ts +27 -0
  38. package/dist/tools/swift/getHoverInfo.js +40 -0
  39. package/dist/tools/swift/getHoverInfo.js.map +1 -0
  40. package/dist/tools/swift/getSymbolDefinition.d.ts +46 -0
  41. package/dist/tools/swift/getSymbolDefinition.js +68 -0
  42. package/dist/tools/swift/getSymbolDefinition.js.map +1 -0
  43. package/dist/tools/swift/getSymbolsOverview.d.ts +22 -0
  44. package/dist/tools/swift/getSymbolsOverview.js +33 -0
  45. package/dist/tools/swift/getSymbolsOverview.js.map +1 -0
  46. package/dist/tools/swift/index.d.ts +14 -0
  47. package/dist/tools/swift/index.js +15 -0
  48. package/dist/tools/swift/index.js.map +1 -0
  49. package/dist/tools/swift/searchPattern.d.ts +38 -0
  50. package/dist/tools/swift/searchPattern.js +71 -0
  51. package/dist/tools/swift/searchPattern.js.map +1 -0
  52. package/package.json +5 -2
@@ -0,0 +1,161 @@
1
+ /**
2
+ * Typed wrappers around the LSP methods we use.
3
+ *
4
+ * Imports types from `vscode-languageserver-protocol` and converts to/from
5
+ * the file:// URI format LSP servers expect. All paths in the public API
6
+ * are absolute filesystem paths; LSP URIs only show up internally.
7
+ */
8
+ import { resolve as resolvePath } from "node:path";
9
+ import { pathToFileURL, fileURLToPath } from "node:url";
10
+ import { SymbolKind, } from "vscode-languageserver-protocol";
11
+ const SYMBOL_KIND_NAMES = {
12
+ [SymbolKind.File]: "file",
13
+ [SymbolKind.Module]: "module",
14
+ [SymbolKind.Namespace]: "namespace",
15
+ [SymbolKind.Package]: "package",
16
+ [SymbolKind.Class]: "class",
17
+ [SymbolKind.Method]: "method",
18
+ [SymbolKind.Property]: "property",
19
+ [SymbolKind.Field]: "field",
20
+ [SymbolKind.Constructor]: "constructor",
21
+ [SymbolKind.Enum]: "enum",
22
+ [SymbolKind.Interface]: "interface",
23
+ [SymbolKind.Function]: "function",
24
+ [SymbolKind.Variable]: "variable",
25
+ [SymbolKind.Constant]: "constant",
26
+ [SymbolKind.String]: "string",
27
+ [SymbolKind.Number]: "number",
28
+ [SymbolKind.Boolean]: "boolean",
29
+ [SymbolKind.Array]: "array",
30
+ [SymbolKind.Object]: "object",
31
+ [SymbolKind.Key]: "key",
32
+ [SymbolKind.Null]: "null",
33
+ [SymbolKind.EnumMember]: "enum-member",
34
+ [SymbolKind.Struct]: "struct",
35
+ [SymbolKind.Event]: "event",
36
+ [SymbolKind.Operator]: "operator",
37
+ [SymbolKind.TypeParameter]: "type-parameter",
38
+ };
39
+ function uriOf(filePath) {
40
+ return pathToFileURL(resolvePath(filePath)).href;
41
+ }
42
+ function pathOf(uri) {
43
+ return fileURLToPath(uri);
44
+ }
45
+ /** LSP `textDocument/definition` — returns 0+ source locations. */
46
+ export async function lspDefinition(client, filePath, line, character) {
47
+ client.didOpen(filePath);
48
+ const params = {
49
+ textDocument: { uri: uriOf(filePath) },
50
+ position: { line, character },
51
+ };
52
+ const result = await client.sendRequest("textDocument/definition", params);
53
+ return locationsToArray(result);
54
+ }
55
+ /** LSP `textDocument/references` — returns all references in indexed projects. */
56
+ export async function lspReferences(client, filePath, line, character, includeDeclaration = true) {
57
+ client.didOpen(filePath);
58
+ const params = {
59
+ textDocument: { uri: uriOf(filePath) },
60
+ position: { line, character },
61
+ context: { includeDeclaration },
62
+ };
63
+ const result = await client.sendRequest("textDocument/references", params);
64
+ return locationsToArray(result);
65
+ }
66
+ /** LSP `textDocument/hover` — returns type info / docs at a position. */
67
+ export async function lspHover(client, filePath, line, character) {
68
+ client.didOpen(filePath);
69
+ const params = {
70
+ textDocument: { uri: uriOf(filePath) },
71
+ position: { line, character },
72
+ };
73
+ const result = await client.sendRequest("textDocument/hover", params);
74
+ if (!result)
75
+ return null;
76
+ const contents = hoverContentsToString(result.contents);
77
+ return { contents };
78
+ }
79
+ /** LSP `textDocument/documentSymbol` — returns top-level + nested symbols. */
80
+ export async function lspDocumentSymbol(client, filePath) {
81
+ client.didOpen(filePath);
82
+ const params = {
83
+ textDocument: { uri: uriOf(filePath) },
84
+ };
85
+ const result = await client.sendRequest("textDocument/documentSymbol", params);
86
+ if (!result)
87
+ return [];
88
+ // Hierarchical case (DocumentSymbol[]).
89
+ if (result.length > 0 && "range" in result[0] && "children" in result[0]) {
90
+ return result.map((s) => docSymbolToResolved(s, filePath));
91
+ }
92
+ // Flat case (SymbolInformation[]).
93
+ return result.map((s) => symInfoToResolved(s));
94
+ }
95
+ function docSymbolToResolved(s, filePath) {
96
+ return {
97
+ name: s.name,
98
+ kind: SYMBOL_KIND_NAMES[s.kind] ?? `kind-${s.kind}`,
99
+ filePath,
100
+ startLine: s.range.start.line,
101
+ startCharacter: s.range.start.character,
102
+ endLine: s.range.end.line,
103
+ endCharacter: s.range.end.character,
104
+ children: s.children?.map((c) => docSymbolToResolved(c, filePath)),
105
+ };
106
+ }
107
+ function symInfoToResolved(s) {
108
+ return {
109
+ name: s.name,
110
+ kind: SYMBOL_KIND_NAMES[s.kind] ?? `kind-${s.kind}`,
111
+ filePath: pathOf(s.location.uri),
112
+ startLine: s.location.range.start.line,
113
+ startCharacter: s.location.range.start.character,
114
+ endLine: s.location.range.end.line,
115
+ endCharacter: s.location.range.end.character,
116
+ };
117
+ }
118
+ function locationsToArray(result) {
119
+ if (!result)
120
+ return [];
121
+ const arr = Array.isArray(result) ? result : [result];
122
+ const out = [];
123
+ for (const item of arr) {
124
+ if ("targetUri" in item) {
125
+ // LocationLink
126
+ out.push({
127
+ filePath: pathOf(item.targetUri),
128
+ line: item.targetSelectionRange.start.line,
129
+ character: item.targetSelectionRange.start.character,
130
+ endLine: item.targetSelectionRange.end.line,
131
+ endCharacter: item.targetSelectionRange.end.character,
132
+ });
133
+ }
134
+ else {
135
+ // Location
136
+ out.push({
137
+ filePath: pathOf(item.uri),
138
+ line: item.range.start.line,
139
+ character: item.range.start.character,
140
+ endLine: item.range.end.line,
141
+ endCharacter: item.range.end.character,
142
+ });
143
+ }
144
+ }
145
+ return out;
146
+ }
147
+ function hoverContentsToString(c) {
148
+ if (!c)
149
+ return "";
150
+ if (typeof c === "string")
151
+ return c;
152
+ if (Array.isArray(c)) {
153
+ return c
154
+ .map((part) => (typeof part === "string" ? part : part.value))
155
+ .join("\n");
156
+ }
157
+ if ("value" in c)
158
+ return c.value;
159
+ return "";
160
+ }
161
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"protocol.js","sourceRoot":"","sources":["../../../src/runtime/sourcekit/protocol.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,21 @@
1
1
  import { z } from "zod";
2
+ import { type Verbosity } from "../parsers/shortenClassName.js";
2
3
  import type { LeaksReport } from "../types.js";
3
4
  export declare const analyzeMemgraphSchema: z.ZodObject<{
4
5
  path: z.ZodString;
5
6
  fullChains: z.ZodDefault<z.ZodBoolean>;
7
+ verbosity: z.ZodDefault<z.ZodEnum<["compact", "normal", "full"]>>;
8
+ maxClassesInChain: z.ZodDefault<z.ZodNumber>;
6
9
  }, "strip", z.ZodTypeAny, {
7
10
  path: string;
8
11
  fullChains: boolean;
12
+ verbosity: "compact" | "normal" | "full";
13
+ maxClassesInChain: number;
9
14
  }, {
10
15
  path: string;
11
16
  fullChains?: boolean | undefined;
17
+ verbosity?: "compact" | "normal" | "full" | undefined;
18
+ maxClassesInChain?: number | undefined;
12
19
  }>;
13
20
  export type AnalyzeMemgraphInput = z.infer<typeof analyzeMemgraphSchema>;
14
21
  export interface CycleSummary {
@@ -19,8 +26,10 @@ export interface CycleSummary {
19
26
  instanceSize?: number;
20
27
  /** Number of descendant nodes in the retain chain. */
21
28
  chainLength: number;
22
- /** Class names appearing anywhere in the chain (deduped). */
29
+ /** Top-ranked class names appearing in the chain (capped, app-level priority). */
23
30
  classesInChain: string[];
31
+ /** Total unique class names found in the chain (the cap-aware count for context). */
32
+ classesInChainTotal: number;
24
33
  }
25
34
  export interface AnalyzeMemgraphResult {
26
35
  ok: boolean;
@@ -45,5 +54,5 @@ export interface AnalyzeMemgraphResult {
45
54
  * Pure function: take a `leaks` stdout string and a source path, produce a structured analysis.
46
55
  * Split out so it can be tested without spawning a subprocess.
47
56
  */
48
- export declare function summarizeLeaks(leaksText: string, path: string, fullChains?: boolean): AnalyzeMemgraphResult;
57
+ export declare function summarizeLeaks(leaksText: string, path: string, fullChains?: boolean, verbosity?: Verbosity, maxClassesInChain?: number): AnalyzeMemgraphResult;
49
58
  export declare function analyzeMemgraph(input: AnalyzeMemgraphInput): Promise<AnalyzeMemgraphResult>;
@@ -3,6 +3,7 @@ import { existsSync } from "node:fs";
3
3
  import { resolve as resolvePath } from "node:path";
4
4
  import { runCommand } from "../runtime/exec.js";
5
5
  import { parseLeaksOutput, rootCyclesOnly } from "../parsers/leaksOutput.js";
6
+ import { shortenForVerbosity, } from "../parsers/shortenClassName.js";
6
7
  export const analyzeMemgraphSchema = z.object({
7
8
  path: z
8
9
  .string()
@@ -12,15 +13,26 @@ export const analyzeMemgraphSchema = z.object({
12
13
  .boolean()
13
14
  .default(false)
14
15
  .describe("When true, include the full nested retain chains in the response. Default false returns only top-level ROOT CYCLE summaries to keep payloads small."),
16
+ verbosity: z
17
+ .enum(["compact", "normal", "full"])
18
+ .default("compact")
19
+ .describe("Class-name verbosity. `compact` (default) drops module prefixes, collapses nested SwiftUI ModifiedContent into `+N modifiers`, and truncates deep generics with a hash placeholder. `normal` keeps more detail. `full` returns Swift demangled names verbatim."),
20
+ maxClassesInChain: z
21
+ .number()
22
+ .int()
23
+ .positive()
24
+ .max(50)
25
+ .default(10)
26
+ .describe("Cap on how many unique class names to surface per cycle's `classesInChain` array. Default 10 — enough to identify app-level types without flooding the response."),
15
27
  });
16
28
  /**
17
29
  * Pure function: take a `leaks` stdout string and a source path, produce a structured analysis.
18
30
  * Split out so it can be tested without spawning a subprocess.
19
31
  */
20
- export function summarizeLeaks(leaksText, path, fullChains = false) {
32
+ export function summarizeLeaks(leaksText, path, fullChains = false, verbosity = "compact", maxClassesInChain = 10) {
21
33
  const report = parseLeaksOutput(leaksText);
22
34
  const roots = rootCyclesOnly(report.cycles);
23
- const cycles = roots.map((c) => summarizeCycle(c));
35
+ const cycles = roots.map((c) => summarizeCycle(c, verbosity, maxClassesInChain));
24
36
  const diagnosis = buildDiagnosis(report, cycles);
25
37
  return {
26
38
  ok: true,
@@ -39,25 +51,41 @@ export function summarizeLeaks(leaksText, path, fullChains = false) {
39
51
  diagnosis,
40
52
  };
41
53
  }
42
- function summarizeCycle(node) {
43
- const classes = new Set();
54
+ function summarizeCycle(node, verbosity, maxClassesInChain) {
55
+ const classCounts = new Map();
44
56
  let chainLength = 0;
45
57
  const visit = (n) => {
46
58
  chainLength += 1;
47
- if (n.className)
48
- classes.add(n.className);
59
+ if (n.className) {
60
+ const short = shortenForVerbosity(n.className, verbosity);
61
+ classCounts.set(short, (classCounts.get(short) ?? 0) + 1);
62
+ }
49
63
  for (const child of n.children)
50
64
  visit(child);
51
65
  };
52
66
  visit(node);
67
+ // Rank classes by occurrence count, take top N. App-level classes (those
68
+ // that don't start with a stdlib prefix even in compact form) get
69
+ // priority since they're the ones the user actually wrote.
70
+ const ranked = Array.from(classCounts.entries())
71
+ .sort((a, b) => {
72
+ const aIsApp = !/^(_DictionaryStorage|Closure|ForEach|Modified|AsyncImage|StoredLocation|LocationBox|TagIndex|AnyHashable|WeakBox|AnyLocation)/.test(a[0]);
73
+ const bIsApp = !/^(_DictionaryStorage|Closure|ForEach|Modified|AsyncImage|StoredLocation|LocationBox|TagIndex|AnyHashable|WeakBox|AnyLocation)/.test(b[0]);
74
+ if (aIsApp !== bIsApp)
75
+ return aIsApp ? -1 : 1;
76
+ return b[1] - a[1];
77
+ })
78
+ .slice(0, maxClassesInChain)
79
+ .map(([name]) => name);
53
80
  return {
54
- className: node.className,
81
+ className: shortenForVerbosity(node.className, verbosity),
55
82
  address: node.address,
56
83
  count: node.count,
57
84
  size: node.size,
58
85
  instanceSize: node.instanceSize,
59
86
  chainLength,
60
- classesInChain: Array.from(classes),
87
+ classesInChain: ranked,
88
+ classesInChainTotal: classCounts.size,
61
89
  };
62
90
  }
63
91
  function buildDiagnosis(report, cycles) {
@@ -89,6 +117,6 @@ export async function analyzeMemgraph(input) {
89
117
  if (result.code !== 0 && result.code !== 1) {
90
118
  throw new Error(`leaks failed (code ${result.code}): ${result.stderr || result.stdout}`);
91
119
  }
92
- return summarizeLeaks(result.stdout, path, input.fullChains ?? false);
120
+ return summarizeLeaks(result.stdout, path, input.fullChains ?? false, input.verbosity ?? "compact", input.maxClassesInChain ?? 10);
93
121
  }
94
122
  //# sourceMappingURL=analyzeMemgraph.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"analyzeMemgraph.js","sourceRoot":"","sources":["../../src/tools/analyzeMemgraph.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"analyzeMemgraph.js","sourceRoot":"","sources":["../../src/tools/analyzeMemgraph.ts"],"names":[],"mappings":"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"}
@@ -1,16 +1,20 @@
1
1
  import { z } from "zod";
2
+ import { type Verbosity } from "../parsers/shortenClassName.js";
2
3
  export declare const findCyclesSchema: z.ZodObject<{
3
4
  path: z.ZodString;
4
5
  className: z.ZodOptional<z.ZodString>;
5
6
  maxDepth: z.ZodDefault<z.ZodNumber>;
7
+ verbosity: z.ZodDefault<z.ZodEnum<["compact", "normal", "full"]>>;
6
8
  }, "strip", z.ZodTypeAny, {
7
- path: string;
8
9
  maxDepth: number;
10
+ path: string;
11
+ verbosity: "compact" | "normal" | "full";
9
12
  className?: string | undefined;
10
13
  }, {
11
14
  path: string;
12
15
  className?: string | undefined;
13
16
  maxDepth?: number | undefined;
17
+ verbosity?: "compact" | "normal" | "full" | undefined;
14
18
  }>;
15
19
  export type FindCyclesInput = z.infer<typeof findCyclesSchema>;
16
20
  export interface CycleChainEntry {
@@ -41,5 +45,5 @@ export interface FindCyclesResult {
41
45
  cycles: CycleResult[];
42
46
  }
43
47
  /** Pure function: parse `leaks` output and return the cycles array. */
44
- export declare function extractCycles(leaksText: string, path: string, filter?: string, maxDepth?: number): FindCyclesResult;
48
+ export declare function extractCycles(leaksText: string, path: string, filter?: string, maxDepth?: number, verbosity?: Verbosity): FindCyclesResult;
45
49
  export declare function findCycles(input: FindCyclesInput): Promise<FindCyclesResult>;
@@ -3,6 +3,7 @@ import { existsSync } from "node:fs";
3
3
  import { resolve as resolvePath } from "node:path";
4
4
  import { runCommand } from "../runtime/exec.js";
5
5
  import { parseLeaksOutput, rootCyclesOnly, walkCycles, } from "../parsers/leaksOutput.js";
6
+ import { shortenForVerbosity, } from "../parsers/shortenClassName.js";
6
7
  export const findCyclesSchema = z.object({
7
8
  path: z.string().min(1).describe("Absolute path to a `.memgraph` file."),
8
9
  className: z
@@ -15,8 +16,12 @@ export const findCyclesSchema = z.object({
15
16
  .positive()
16
17
  .default(10)
17
18
  .describe("Truncate chains beyond this depth (default 10)."),
19
+ verbosity: z
20
+ .enum(["compact", "normal", "full"])
21
+ .default("compact")
22
+ .describe("Class-name verbosity. `compact` shortens SwiftUI generic names aggressively; `full` returns demangled names verbatim."),
18
23
  });
19
- function flattenChain(node, maxDepth) {
24
+ function flattenChain(node, maxDepth, verbosity) {
20
25
  const out = [];
21
26
  for (const { node: n, depth } of walkCycles([node])) {
22
27
  if (depth > maxDepth)
@@ -25,7 +30,7 @@ function flattenChain(node, maxDepth) {
25
30
  depth,
26
31
  edge: n.edge,
27
32
  retainKind: n.retainKind,
28
- className: n.className,
33
+ className: shortenForVerbosity(n.className, verbosity),
29
34
  address: n.address,
30
35
  count: n.count,
31
36
  size: n.size,
@@ -36,16 +41,16 @@ function flattenChain(node, maxDepth) {
36
41
  return out;
37
42
  }
38
43
  /** Pure function: parse `leaks` output and return the cycles array. */
39
- export function extractCycles(leaksText, path, filter, maxDepth = 10) {
44
+ export function extractCycles(leaksText, path, filter, maxDepth = 10, verbosity = "compact") {
40
45
  const report = parseLeaksOutput(leaksText);
41
46
  const roots = rootCyclesOnly(report.cycles);
42
47
  const cycles = roots.map((c) => {
43
- const chain = flattenChain(c, maxDepth);
48
+ const chain = flattenChain(c, maxDepth, verbosity);
44
49
  const matched = filter
45
50
  ? chain.some((entry) => entry.className.includes(filter))
46
51
  : true;
47
52
  return {
48
- rootClass: c.className,
53
+ rootClass: shortenForVerbosity(c.className, verbosity),
49
54
  rootAddress: c.address,
50
55
  count: c.count,
51
56
  size: c.size,
@@ -73,6 +78,6 @@ export async function findCycles(input) {
73
78
  if (result.code !== 0 && result.code !== 1) {
74
79
  throw new Error(`leaks failed (code ${result.code}): ${result.stderr || result.stdout}`);
75
80
  }
76
- return extractCycles(result.stdout, path, input.className, input.maxDepth ?? 10);
81
+ return extractCycles(result.stdout, path, input.className, input.maxDepth ?? 10, input.verbosity ?? "compact");
77
82
  }
78
83
  //# sourceMappingURL=findCycles.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"findCycles.js","sourceRoot":"","sources":["../../src/tools/findCycles.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"findCycles.js","sourceRoot":"","sources":["../../src/tools/findCycles.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ import { z } from "zod";
2
+ import type { LeaksReport } from "../types.js";
3
+ /**
4
+ * Cycle-scoped reachability + class counting.
5
+ *
6
+ * Answers questions like:
7
+ * "How many `NSURLSessionConfiguration` instances are reachable from the
8
+ * cycle rooted at `DetailViewModel`?"
9
+ *
10
+ * Where global `countAlive` would say "4495 NSURLSessionConfiguration", this
11
+ * tool says "1100 reachable from each of the 4 cycles, so the cycle root is
12
+ * the actual culprit pinning them in memory."
13
+ *
14
+ * API shape inspired by Meta's `memlab` predicate-based queries.
15
+ */
16
+ export declare const reachableFromCycleSchema: z.ZodObject<{
17
+ path: z.ZodString;
18
+ cycleIndex: z.ZodOptional<z.ZodNumber>;
19
+ rootClassName: z.ZodOptional<z.ZodString>;
20
+ className: z.ZodOptional<z.ZodString>;
21
+ topN: z.ZodDefault<z.ZodNumber>;
22
+ verbosity: z.ZodDefault<z.ZodEnum<["compact", "normal", "full"]>>;
23
+ }, "strip", z.ZodTypeAny, {
24
+ path: string;
25
+ verbosity: "compact" | "normal" | "full";
26
+ topN: number;
27
+ className?: string | undefined;
28
+ cycleIndex?: number | undefined;
29
+ rootClassName?: string | undefined;
30
+ }, {
31
+ path: string;
32
+ className?: string | undefined;
33
+ verbosity?: "compact" | "normal" | "full" | undefined;
34
+ topN?: number | undefined;
35
+ cycleIndex?: number | undefined;
36
+ rootClassName?: string | undefined;
37
+ }>;
38
+ export type ReachableFromCycleInput = z.infer<typeof reachableFromCycleSchema>;
39
+ export interface ClassCount {
40
+ className: string;
41
+ count: number;
42
+ }
43
+ export interface ReachableFromCycleResult {
44
+ ok: boolean;
45
+ path: string;
46
+ /** The cycle that was scoped to. */
47
+ cycle: {
48
+ index: number;
49
+ rootClass: string;
50
+ rootAddress: string;
51
+ /** Total reachable nodes from this cycle root (including descendants). */
52
+ totalReachable: number;
53
+ };
54
+ /** When `className` filter is provided, only that class shows up. Otherwise top N. */
55
+ counts: ClassCount[];
56
+ /** Total unique classes in the cycle's reachable set. */
57
+ uniqueClasses: number;
58
+ }
59
+ /** Pure: compute the result from a parsed report. Exposed for testing. */
60
+ export declare function reachableFromReport(report: LeaksReport, path: string, input: ReachableFromCycleInput): ReachableFromCycleResult;
61
+ export declare function reachableFromCycle(input: ReachableFromCycleInput): Promise<ReachableFromCycleResult>;
@@ -0,0 +1,116 @@
1
+ import { z } from "zod";
2
+ import { runLeaksAndParse } from "../runtime/leaks.js";
3
+ import { rootCyclesOnly } from "../parsers/leaksOutput.js";
4
+ import { shortenForVerbosity, } from "../parsers/shortenClassName.js";
5
+ /**
6
+ * Cycle-scoped reachability + class counting.
7
+ *
8
+ * Answers questions like:
9
+ * "How many `NSURLSessionConfiguration` instances are reachable from the
10
+ * cycle rooted at `DetailViewModel`?"
11
+ *
12
+ * Where global `countAlive` would say "4495 NSURLSessionConfiguration", this
13
+ * tool says "1100 reachable from each of the 4 cycles, so the cycle root is
14
+ * the actual culprit pinning them in memory."
15
+ *
16
+ * API shape inspired by Meta's `memlab` predicate-based queries.
17
+ */
18
+ export const reachableFromCycleSchema = z.object({
19
+ path: z.string().min(1).describe("Absolute path to a `.memgraph` file."),
20
+ cycleIndex: z
21
+ .number()
22
+ .int()
23
+ .nonnegative()
24
+ .optional()
25
+ .describe("Zero-based index of the ROOT CYCLE to scope to. Mutually exclusive with `rootClassName`. When neither is given, defaults to cycle index 0."),
26
+ rootClassName: z
27
+ .string()
28
+ .optional()
29
+ .describe("Substring of the root cycle's class name (e.g. \"DetailViewModel\"). Picks the first ROOT CYCLE whose root matches. Mutually exclusive with `cycleIndex`."),
30
+ className: z
31
+ .string()
32
+ .optional()
33
+ .describe("Optional filter — only count nodes whose className contains this substring. When omitted, returns the full per-class breakdown."),
34
+ topN: z
35
+ .number()
36
+ .int()
37
+ .positive()
38
+ .max(100)
39
+ .default(20)
40
+ .describe("Cap on per-class entries returned (default 20)."),
41
+ verbosity: z
42
+ .enum(["compact", "normal", "full"])
43
+ .default("compact")
44
+ .describe("Class-name verbosity for the response. See analyzeMemgraph for the same flag."),
45
+ });
46
+ /** Pure: walk the tree from root, count nodes by className. */
47
+ function countReachableFromNode(root, verbosity) {
48
+ const counts = new Map();
49
+ let total = 0;
50
+ const visit = (n) => {
51
+ total += 1;
52
+ if (n.className) {
53
+ const short = shortenForVerbosity(n.className, verbosity);
54
+ counts.set(short, (counts.get(short) ?? 0) + 1);
55
+ }
56
+ for (const child of n.children)
57
+ visit(child);
58
+ };
59
+ visit(root);
60
+ return { byClass: counts, total };
61
+ }
62
+ function pickCycle(report, input) {
63
+ const roots = rootCyclesOnly(report.cycles);
64
+ if (roots.length === 0)
65
+ return null;
66
+ if (input.rootClassName) {
67
+ const idx = roots.findIndex((r) => r.className.includes(input.rootClassName));
68
+ if (idx >= 0)
69
+ return { node: roots[idx], index: idx };
70
+ return null;
71
+ }
72
+ const idx = input.cycleIndex ?? 0;
73
+ if (idx >= roots.length)
74
+ return null;
75
+ return { node: roots[idx], index: idx };
76
+ }
77
+ /** Pure: compute the result from a parsed report. Exposed for testing. */
78
+ export function reachableFromReport(report, path, input) {
79
+ const picked = pickCycle(report, input);
80
+ if (!picked) {
81
+ throw new Error(input.rootClassName
82
+ ? `No ROOT CYCLE found whose root class contains "${input.rootClassName}".`
83
+ : `No ROOT CYCLE at index ${input.cycleIndex ?? 0}. Available roots: ${rootCyclesOnly(report.cycles).length}.`);
84
+ }
85
+ const verbosity = input.verbosity ?? "compact";
86
+ const { byClass, total } = countReachableFromNode(picked.node, verbosity);
87
+ let entries = Array.from(byClass.entries()).map(([n, c]) => ({
88
+ className: n,
89
+ count: c,
90
+ }));
91
+ if (input.className) {
92
+ entries = entries.filter((e) => e.className.includes(input.className));
93
+ }
94
+ entries.sort((a, b) => b.count - a.count);
95
+ entries = entries.slice(0, input.topN ?? 20);
96
+ return {
97
+ ok: true,
98
+ path,
99
+ cycle: {
100
+ index: picked.index,
101
+ rootClass: shortenForVerbosity(picked.node.className, verbosity),
102
+ rootAddress: picked.node.address,
103
+ totalReachable: total,
104
+ },
105
+ counts: entries,
106
+ uniqueClasses: byClass.size,
107
+ };
108
+ }
109
+ export async function reachableFromCycle(input) {
110
+ if (input.cycleIndex !== undefined && input.rootClassName !== undefined) {
111
+ throw new Error("Provide either `cycleIndex` or `rootClassName`, not both.");
112
+ }
113
+ const { report, resolvedPath } = await runLeaksAndParse(input.path);
114
+ return reachableFromReport(report, resolvedPath, input);
115
+ }
116
+ //# sourceMappingURL=reachableFromCycle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reachableFromCycle.js","sourceRoot":"","sources":["../../src/tools/reachableFromCycle.ts"],"names":[],"mappings":"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"}
@@ -7,8 +7,8 @@ export declare const renderCycleGraphSchema: z.ZodObject<{
7
7
  maxDepth: z.ZodDefault<z.ZodNumber>;
8
8
  truncateClassName: z.ZodDefault<z.ZodNumber>;
9
9
  }, "strip", z.ZodTypeAny, {
10
- path: string;
11
10
  maxDepth: number;
11
+ path: string;
12
12
  cycleIndex: number;
13
13
  format: "mermaid" | "dot";
14
14
  truncateClassName: number;