Skip to content

Commit

Permalink
feat: Addition of XHR/feat Breakpoints (#1856)
Browse files Browse the repository at this point in the history
* feat: addition of XHR/feat Breakpoints

* rebase

* update

* Implementing @connor4312 idea

* removal of old XHR Breakpoint UI

* revert package lock

* implementing @connor4312 suggestions

* clean and implement

* some cleanups

---------

Co-authored-by: Connor Peet <connor@peet.io>
  • Loading branch information
OnesAndZer0s and connor4312 authored Nov 27, 2023
1 parent 6d44bd0 commit f1996b8
Show file tree
Hide file tree
Showing 18 changed files with 332 additions and 56 deletions.
7 changes: 6 additions & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
{
"add.eventListener.breakpoint": "Toggle Event Listener Breakpoints",
"add.xhr.breakpoint": "Add XHR/fetch Breakpoint",
"breakpoint.xhr.contains":"Break when URL contains:",
"breakpoint.xhr.any":"Any XHR/fetch",
"edit.xhr.breakpoint": "Edit XHR/fetch Breakpoint",
"attach.node.process": "Attach to Node Process",
"base.cascadeTerminateToConfigurations.label": "A list of debug sessions which, when this debug session is terminated, will also be stopped.",
"base.enableDWARF.label": "Toggles whether the debugger will try to read DWARF debug symbols from WebAssembly, which can be resource intensive. Requires the `ms-vscode.wasm-dwarf-debugging` extension to function.",
Expand Down Expand Up @@ -186,7 +190,8 @@
"profile.start": "Take Performance Profile",
"profile.stop": "Stop Performance Profile",
"remove.eventListener.breakpoint.all": "Remove All Event Listener Breakpoints",
"remove.eventListener.breakpoint": "Remove Event Listener Breakpoint",
"remove.xhr.breakpoint.all": "Remove All XHR/fetch Breakpoints",
"remove.xhr.breakpoint": "Remove XHR/fetch Breakpoint",
"requestCDPProxy.label": "Request CDP Proxy for Debug Session",
"skipFiles.description": "An array of glob patterns for files to skip when debugging. The pattern `<node_internals>/**` matches all internal Node.js modules.",
"smartStep.description": "Automatically step through generated code that cannot be mapped back to the original source.",
Expand Down
4 changes: 3 additions & 1 deletion src/adapter/customBreakpoints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@
import * as l10n from '@vscode/l10n';
import Cdp from '../cdp/api';

export type CustomBreakpointId = string;
export interface IXHRBreakpoint {
match: string;
}

export interface ICustomBreakpoint {
id: string;
Expand Down
11 changes: 6 additions & 5 deletions src/adapter/debugAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ export class DebugAdapter implements IDisposable {
readonly breakpointManager: BreakpointManager;
private _disposables = new DisposableList();
private _customBreakpoints: string[] = [];
private _xhrBreakpoints: string[] = [];
private _thread: Thread | undefined;
private _threadDeferred = getDeferred<Thread>();
private _configurationDoneDeferred: IDeferred<void>;
Expand Down Expand Up @@ -103,6 +104,7 @@ export class DebugAdapter implements IDisposable {
this.dap.on('exceptionInfo', () => this._withThread(thread => thread.exceptionInfo()));
this.dap.on('setCustomBreakpoints', params => this.setCustomBreakpoints(params));
this.dap.on('toggleSkipFileStatus', params => this._toggleSkipFileStatus(params));
this.dap.on('toggleSkipFileStatus', params => this._toggleSkipFileStatus(params));
this.dap.on('prettyPrintSource', params => this._prettyPrintSource(params));
this.dap.on('revealPage', () => this._withThread(thread => thread.revealPage()));
this.dap.on('getPerformance', () =>
Expand Down Expand Up @@ -455,7 +457,7 @@ export class DebugAdapter implements IDisposable {
profile.start(this.dap, this._thread, { type: BasicCpuProfiler.type });
}

this._thread.updateCustomBreakpoints(this._customBreakpoints);
this._thread.updateCustomBreakpoints(this._xhrBreakpoints, this._customBreakpoints);

this.asyncStackPolicy
.connect(cdp)
Expand All @@ -475,12 +477,11 @@ export class DebugAdapter implements IDisposable {

async setCustomBreakpoints({
ids,
xhr,
}: Dap.SetCustomBreakpointsParams): Promise<Dap.SetCustomBreakpointsResult> {
await this._thread?.updateCustomBreakpoints(xhr, ids);
this._customBreakpoints = ids;
if (this._thread) {
await this._thread.updateCustomBreakpoints(ids);
}

this._xhrBreakpoints = xhr;
return {};
}

Expand Down
33 changes: 27 additions & 6 deletions src/adapter/threads.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { BreakpointManager, EntryBreakpointMode } from './breakpoints';
import { UserDefinedBreakpoint } from './breakpoints/userDefinedBreakpoint';
import { ICompletions } from './completions';
import { ExceptionMessage, IConsole, QueryObjectsMessage } from './console';
import { CustomBreakpointId, customBreakpoints } from './customBreakpoints';
import { customBreakpoints } from './customBreakpoints';
import { IEvaluator } from './evaluator';
import { IExceptionPauseService } from './exceptionPauseService';
import * as objectPreview from './objectPreview';
Expand Down Expand Up @@ -156,6 +156,11 @@ class StateQueue {
}
}

const enum CustomBreakpointPrefix {
XHR = 'x',
Event = 'e',
}

export class Thread implements IVariableStoreLocationProvider {
private static _lastThreadId = 0;
public readonly id: number;
Expand All @@ -173,7 +178,7 @@ export class Thread implements IVariableStoreLocationProvider {
private _sourceMapDisabler?: SourceMapDisabler;
private _expectedPauseReason?: ExpectedPauseReason;
private _excludedCallers: readonly Dap.ExcludedCaller[] = [];
private _enabledCustomBreakpoints?: ReadonlySet<CustomBreakpointId>;
private _enabledCustomBreakpoints?: ReadonlySet<string>;
private readonly stateQueue = new StateQueue();
private readonly _onPausedEmitter = new EventEmitter<IPausedDetails>();
private readonly _dap: DeferredContainer<Dap.Api>;
Expand Down Expand Up @@ -1250,23 +1255,39 @@ export class Thread implements IVariableStoreLocationProvider {
return `@ VM${raw.scriptId || 'XX'}:${raw.lineNumber}`;
}

async updateCustomBreakpoints(ids: CustomBreakpointId[]): Promise<void> {
async updateCustomBreakpoints(xhr: string[], events: string[]): Promise<void> {
if (!this.target.supportsCustomBreakpoints()) return;
this._enabledCustomBreakpoints ??= new Set();

// Do not fail for custom breakpoints, to account for
// future changes in cdp vs stale breakpoints saved in the workspace.
const newIds = new Set(ids);
const newIds = new Set<string>();
for (const x of xhr) {
newIds.add(CustomBreakpointPrefix.XHR + x);
}
for (const e of events) {
newIds.add(CustomBreakpointPrefix.Event + e);
}
const todo: (Promise<unknown> | undefined)[] = [];

for (const newId of newIds) {
if (!this._enabledCustomBreakpoints.has(newId)) {
todo.push(customBreakpoints().get(newId)?.apply(this._cdp, true));
const id = newId.slice(CustomBreakpointPrefix.XHR.length);
todo.push(
newId.startsWith(CustomBreakpointPrefix.XHR)
? this._cdp.DOMDebugger.setXHRBreakpoint({ url: id })
: customBreakpoints().get(id)?.apply(this._cdp, true),
);
}
}
for (const oldId of this._enabledCustomBreakpoints) {
if (!newIds.has(oldId)) {
todo.push(customBreakpoints().get(oldId)?.apply(this._cdp, false));
const id = oldId.slice(CustomBreakpointPrefix.XHR.length);
todo.push(
oldId.startsWith(CustomBreakpointPrefix.XHR)
? this._cdp.DOMDebugger.removeXHRBreakpoint({ url: id })
: customBreakpoints().get(id)?.apply(this._cdp, false),
);
}
}

Expand Down
9 changes: 8 additions & 1 deletion src/build/dapCustom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,15 @@ const dapCustom: JSONSchema4 = {
},
description: 'Id of breakpoints that should be enabled.',
},
xhr: {
type: 'array',
items: {
type: 'string',
},
description: 'strings of XHR breakpoints that should be enabled.',
},
},
required: ['ids'],
required: ['ids', 'xhr'],
}),

...makeRequest('prettyPrintSource', 'Pretty prints source for debugging.', {
Expand Down
64 changes: 53 additions & 11 deletions src/build/generate-contributions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,21 @@
import { JSONSchema6, JSONSchema6Definition } from 'json-schema';
import type strings from '../../package.nls.json';
import {
allCommands,
allDebugTypes,
AutoAttachMode,
Commands,
Configuration,
ContextKey,
CustomViews,
DebugType,
IConfigurationTypes,
allCommands,
allDebugTypes,
preferredDebugTypes,
} from '../common/contributionUtils';
import { knownToolToken } from '../common/knownTools';
import { mapValues, sortKeys, walkObject } from '../common/objUtils';
import {
AnyLaunchConfiguration,
baseDefaults,
breakpointLanguages,
chromeAttachConfigDefaults,
chromeLaunchConfigDefaults,
edgeAttachConfigDefaults,
edgeLaunchConfigDefaults,
extensionHostConfigDefaults,
IBaseConfiguration,
IChromeAttachConfiguration,
IChromeLaunchConfiguration,
Expand All @@ -39,10 +32,17 @@ import {
INodeLaunchConfiguration,
ITerminalLaunchConfiguration,
KillBehavior,
nodeAttachConfigDefaults,
nodeLaunchConfigDefaults,
OutputSource,
ResolvingConfiguration,
baseDefaults,
breakpointLanguages,
chromeAttachConfigDefaults,
chromeLaunchConfigDefaults,
edgeAttachConfigDefaults,
edgeLaunchConfigDefaults,
extensionHostConfigDefaults,
nodeAttachConfigDefaults,
nodeLaunchConfigDefaults,
terminalBaseDefaults,
} from '../configuration';

Expand Down Expand Up @@ -1232,6 +1232,21 @@ const commands: ReadonlyArray<{
title: refString('remove.eventListener.breakpoint.all'),
icon: '$(close-all)',
},
{
command: Commands.AddXHRBreakpoints,
title: refString('add.xhr.breakpoint'),
icon: '$(add)',
},
{
command: Commands.RemoveXHRBreakpoints,
title: refString('remove.xhr.breakpoint'),
icon: '$(remove)',
},
{
command: Commands.EditXHRBreakpoint,
title: refString('edit.xhr.breakpoint'),
icon: '$(edit)',
},
{
command: Commands.AttachProcess,
title: refString('attach.node.process'),
Expand Down Expand Up @@ -1474,6 +1489,33 @@ const menus: Menus = {
},
],
'view/item/context': [
{
command: Commands.AddXHRBreakpoints,
when: `view == ${CustomViews.EventListenerBreakpoints} && viewItem == xhrBreakpoint`,
},
{
command: Commands.EditXHRBreakpoint,
when: `view == ${CustomViews.EventListenerBreakpoints} && viewItem == xhrBreakpoint`,
group: 'inline',
},
{
command: Commands.EditXHRBreakpoint,
when: `view == ${CustomViews.EventListenerBreakpoints} && viewItem == xhrBreakpoint`,
},
{
command: Commands.RemoveXHRBreakpoints,
when: `view == ${CustomViews.EventListenerBreakpoints} && viewItem == xhrBreakpoint`,
group: 'inline',
},
{
command: Commands.RemoveXHRBreakpoints,
when: `view == ${CustomViews.EventListenerBreakpoints} && viewItem == xhrBreakpoint`,
},
{
command: Commands.AddXHRBreakpoints,
when: `view == ${CustomViews.EventListenerBreakpoints} && viewItem == xhrCategory`,
group: 'inline',
},
{
command: Commands.CallersGoToCaller,
group: 'inline',
Expand Down
32 changes: 30 additions & 2 deletions src/cdp/api.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1703,6 +1703,8 @@ export namespace Cdp {
| 'IdTokenHttpNotFound'
| 'IdTokenNoResponse'
| 'IdTokenInvalidResponse'
| 'IdTokenIdpErrorResponse'
| 'IdTokenCrossSiteIdpErrorResponse'
| 'IdTokenInvalidRequest'
| 'IdTokenInvalidContentType'
| 'ErrorIdToken'
Expand Down Expand Up @@ -2938,7 +2940,7 @@ export namespace Cdp {

/**
* Definition of PermissionDescriptor defined in the Permissions API:
* https://w3c.github.io/permissions/#dictdef-permissiondescriptor.
* https://w3c.github.io/permissions/#dom-permissiondescriptor.
*/
export interface PermissionDescriptor {
/**
Expand Down Expand Up @@ -23093,6 +23095,7 @@ export namespace Cdp {
| 'unload'
| 'usb'
| 'vertical-scroll'
| 'web-printing'
| 'web-share'
| 'window-management'
| 'window-placement'
Expand Down Expand Up @@ -24323,6 +24326,8 @@ export namespace Cdp {
* that is incompatible with prerender and has caused the cancellation of the attempt.
*/
disallowedMojoInterface?: string;

mismatchedHeaders?: PrerenderMismatchedHeaders[];
}

/**
Expand Down Expand Up @@ -24557,6 +24562,17 @@ export namespace Cdp {
| 'PrefetchResponseUsed'
| 'PrefetchSuccessfulButNotUsed'
| 'PrefetchNotUsedProbeFailed';

/**
* Information of headers to be displayed when the header mismatch occurred.
*/
export interface PrerenderMismatchedHeaders {
headerName: string;

initialValue?: string;

activationValue?: string;
}
}

/**
Expand Down Expand Up @@ -27424,6 +27440,8 @@ export namespace Cdp {
controlledClients?: Target.TargetID[];

targetId?: Target.TargetID;

routerRules?: string;
}

/**
Expand Down Expand Up @@ -28700,6 +28718,16 @@ export namespace Cdp {
ends: integer[];
}

export interface AttributionReportingTriggerSpec {
/**
* number instead of integer because not all uint32 can be represented by
* int
*/
triggerData: number[];

eventReportWindows: AttributionReportingEventReportWindows;
}

export type AttributionReportingTriggerDataMatching = 'exact' | 'modulus';

export interface AttributionReportingSourceRegistration {
Expand All @@ -28710,7 +28738,7 @@ export namespace Cdp {
*/
expiry: integer;

eventReportWindows: AttributionReportingEventReportWindows;
triggerSpecs: AttributionReportingTriggerSpec[];

/**
* duration in seconds
Expand Down
Loading

0 comments on commit f1996b8

Please sign in to comment.