/** * Parser for `leaks --debug=stacks --debug='$'` output. * * This is the canonical way to get the allocation stack + retainer list for * a specific class without it being part of a strict cycle. The notelet * investigation's `342 to 0 AVPlayerItem` count came from running this * command directly + grepping `_objc_rootAllocWithZone | wc -l`. v1.12 * automates the parse + aggregates by call-stack fingerprint so the * response is a small structured list instead of 342 verbose blocks. * * Output shape (per SCANNING block): * * ```text * SCANNING [size] * Call stack: 0xADDR (dyld) start | 0xADDR (...) ??? | ... * REFERENCES TO THIS: N STRONG: X CONSERVATIVE: Y WEAK UU etc: Z * [size] +offset: edge-name 0xADDR * ... * CONTENTS: * +offset: field-name 0xADDR --> [size] * ... * ``` * * Multiple SCANNING blocks (one per instance) are aggregated by * call-stack fingerprint. Identical stacks count as one chain with * `instanceCount: N` instead of N duplicates. */ export interface AllocationFrame { /** Hex address of the frame, e.g. "0x100e97da4". */ address: string; /** Image/binary name in parentheses, e.g. "(dyld)" or "(NoteletDemo.debug.dylib)". */ image: string; /** Symbol name when symbolicated, e.g. "_objc_rootAllocWithZone" or "MediaNoteItemVideoView.prepareVideo". `???` when stripped. */ symbol: string; } export interface ReferenceTreeChain { /** How many instances share this exact call-stack fingerprint. */ instanceCount: number; /** * Call-stack frames from outer (root, dyld start) to inner (allocation site). * The leaks output emits them in dyld-first order; we preserve that. */ callStack: AllocationFrame[]; /** A representative instance address for the user to chain into via `leaks `. */ exampleAddress: string; /** Unique retainer classes referenced from THIS instance with how often each appeared across the aggregation group. */ retainers: Array<{ className: string; count: number; }>; /** The "user-actionable" frame: the deepest frame whose image isn't system (dyld, libobjc, libsystem, libdispatch, SwiftUI core runtime). Surfaces the line a developer would inspect. */ userFrame?: AllocationFrame; } /** * Pure: parse a single `Call stack: ...` line into an ordered list of frames. * Frames are pipe-separated; each frame is ` () `. */ export declare function parseCallStackLine(line: string): AllocationFrame[]; /** * Heuristic: pick the user-actionable frame from a call stack. The deepest * (closest to allocation) frame whose image is NOT a system runtime. For * notelet, this resolves to `MediaNoteItemVideoView.prepareVideo` -- the * line in the library that called `AVPlayerItem.init`. */ export declare function pickUserFrame(frames: AllocationFrame[]): AllocationFrame | undefined; /** Pure: parse the full `leaks --debug=stacks` output for a class. */ export declare function parseLeaksDebugStacks(output: string): ReferenceTreeChain[];