chrome-devtools-frontend
Version:
Chrome DevTools UI
161 lines (129 loc) • 4.95 kB
text/typescript
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import * as Common from '../../core/common/common.js';
import type * as SDK from '../../core/sdk/sdk.js';
import type * as Workspace from '../workspace/workspace.js';
import type * as StackTrace from './stack_trace.js';
import type {FrameNode} from './Trie.js';
export type AnyStackTraceImpl = StackTraceImpl<FragmentImpl|DebuggableFragmentImpl>;
export class StackTraceImpl<SyncFragmentT extends FragmentImpl|DebuggableFragmentImpl = FragmentImpl> extends
Common.ObjectWrapper.ObjectWrapper<StackTrace.StackTrace.EventTypes> implements
StackTrace.StackTrace.BaseStackTrace<SyncFragmentT> {
readonly syncFragment: SyncFragmentT;
readonly asyncFragments: readonly AsyncFragmentImpl[];
constructor(syncFragment: SyncFragmentT, asyncFragments: AsyncFragmentImpl[]) {
super();
this.syncFragment = syncFragment;
this.asyncFragments = asyncFragments;
const fragment =
syncFragment instanceof DebuggableFragmentImpl ? syncFragment.fragment : syncFragment as FragmentImpl;
fragment.stackTraces.add(this);
this.asyncFragments.forEach(asyncFragment => asyncFragment.fragment.stackTraces.add(this));
}
}
export class FragmentImpl implements StackTrace.StackTrace.Fragment {
readonly node: FrameNode;
readonly stackTraces = new Set<AnyStackTraceImpl>();
/**
* Fragments are deduplicated based on the node.
*
* In turn, each fragment can be part of multiple stack traces.
*/
static getOrCreate(node: FrameNode): FragmentImpl {
if (!node.fragment) {
node.fragment = new FragmentImpl(node);
}
return node.fragment;
}
private constructor(node: FrameNode) {
this.node = node;
}
get frames(): FrameImpl[] {
const frames: FrameImpl[] = [];
for (const node of this.node.getCallStack()) {
frames.push(...node.frames);
}
return frames;
}
}
export class AsyncFragmentImpl implements StackTrace.StackTrace.AsyncFragment {
constructor(readonly description: string, readonly fragment: FragmentImpl) {
}
get frames(): StackTrace.StackTrace.Frame[] {
return this.fragment.frames;
}
}
export class FrameImpl implements StackTrace.StackTrace.Frame {
readonly url?: string;
readonly uiSourceCode?: Workspace.UISourceCode.UISourceCode;
readonly name?: string;
readonly line: number;
readonly column: number;
readonly missingDebugInfo?: StackTrace.StackTrace.MissingDebugInfo;
constructor(
url: string|undefined, uiSourceCode: Workspace.UISourceCode.UISourceCode|undefined, name: string|undefined,
line: number, column: number, missingDebugInfo?: StackTrace.StackTrace.MissingDebugInfo) {
this.url = url;
this.uiSourceCode = uiSourceCode;
this.name = name;
this.line = line;
this.column = column;
this.missingDebugInfo = missingDebugInfo;
}
}
/**
* A DebuggableFragmentImpl wraps an existing FragmentImpl. This is important: We can pause at the
* same location multiple times and the paused information changes each and everytime while the underlying
* FragmentImpl will stay the same.
*/
export class DebuggableFragmentImpl implements StackTrace.StackTrace.DebuggableFragment {
constructor(readonly fragment: FragmentImpl, private readonly callFrames: SDK.DebuggerModel.CallFrame[]) {
}
get frames(): DebuggableFrameImpl[] {
const frames: DebuggableFrameImpl[] = [];
let index = 0;
for (const node of this.fragment.node.getCallStack()) {
for (const frame of node.frames) {
// Each inlined frame gets the same DebugerModel.CallFrame for debugging.
frames.push(new DebuggableFrameImpl(frame, this.callFrames[index]));
}
index++;
}
return frames;
}
}
/**
* A DebuggableFrameImpl wraps an existing FrameImpl. This is important: We can pause at the
* same location multiple times and the paused information changes each and everytime while the underlying
* FrameImpl will stay the same.
*/
export class DebuggableFrameImpl implements StackTrace.StackTrace.DebuggableFrame {
readonly #frame: FrameImpl;
readonly #sdkFrame: SDK.DebuggerModel.CallFrame;
constructor(frame: FrameImpl, sdkFrame: SDK.DebuggerModel.CallFrame) {
this.#frame = frame;
this.#sdkFrame = sdkFrame;
}
get url(): string|undefined {
return this.#frame.url;
}
get uiSourceCode(): Workspace.UISourceCode.UISourceCode|undefined {
return this.#frame.uiSourceCode;
}
get name(): string|undefined {
return this.#frame.name;
}
get line(): number {
return this.#frame.line;
}
get column(): number {
return this.#frame.column;
}
get missingDebugInfo(): StackTrace.StackTrace.MissingDebugInfo|undefined {
return this.#frame.missingDebugInfo;
}
get sdkFrame(): SDK.DebuggerModel.CallFrame {
return this.#sdkFrame;
}
}