Skip to content

Commit 66a746a

Browse files
committed
chore: make sourcePathResolver function per-thread
1 parent 6379efb commit 66a746a

File tree

7 files changed

+77
-69
lines changed

7 files changed

+77
-69
lines changed

src/adapter/breakpoints.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright (C) Microsoft Corporation. All rights reserved.
33
*--------------------------------------------------------*/
44

5-
import { SourcePathResolver, Location, SourceContainer, Source } from './sources';
5+
import { Location, SourceContainer, Source } from './sources';
66
import Dap from '../dap/api';
77
import Cdp from '../cdp/api';
88
import { Thread, ThreadManager, Script } from './threads';
@@ -71,13 +71,8 @@ export class Breakpoint {
7171
}
7272
}, undefined, this._disposables);
7373

74-
const source = this._manager._sourceContainer.source(this._source);
75-
const url = source
76-
? source.url() :
77-
(this._source.path ? this._manager._sourcePathResolver.absolutePathToUrl(this._source.path) : undefined);
7874
const promises: Promise<void>[] = [];
79-
80-
if (url) {
75+
{
8176
// For breakpoints set before launch, we don't know whether they are in a compiled or
8277
// a source map source. To make them work, we always set by url to not miss compiled.
8378
//
@@ -86,15 +81,17 @@ export class Breakpoint {
8681
const lineNumber = this._lineNumber - 1;
8782
const columnNumber = this._columnNumber - 1;
8883
promises.push(...threadManager.threads().map(thread => {
89-
return this._setByUrl(thread, url, lineNumber, columnNumber);
84+
return this._setByPath(thread, lineNumber, columnNumber);
9085
}));
9186
threadManager.onThreadAdded(thread => {
92-
this._setByUrl(thread, url, lineNumber, columnNumber);
87+
this._setByPath(thread, lineNumber, columnNumber);
9388
}, undefined, this._disposables);
9489
}
9590

91+
const source = this._manager._sourceContainer.source(this._source);
92+
const url = source ? source.url() : '';
9693
const locations = this._manager._sourceContainer.currentSiblingLocations({
97-
url: url || '',
94+
url,
9895
lineNumber: this._lineNumber,
9996
columnNumber: this._columnNumber,
10097
source
@@ -173,6 +170,15 @@ export class Breakpoint {
173170
await Promise.all(promises);
174171
}
175172

173+
async _setByPath(thread: Thread, lineNumber: number, columnNumber: number): Promise<void> {
174+
const source = this._manager._sourceContainer.source(this._source);
175+
const url = source ? source.url() :
176+
(this._source.path ? thread.sourcePathResolver.absolutePathToUrl(this._source.path) : undefined);
177+
if (!url)
178+
return
179+
await this._setByUrl(thread, url, lineNumber, columnNumber);
180+
}
181+
176182
async _setByUrl(thread: Thread, url: string, lineNumber: number, columnNumber: number): Promise<void> {
177183
const activeSetter = (async () => {
178184
const result = await thread.cdp().Debugger.setBreakpointByUrl({
@@ -230,15 +236,13 @@ export class BreakpointManager {
230236
private _byRef: Map<number, Breakpoint[]> = new Map();
231237

232238
_dap: Dap.Api;
233-
_sourcePathResolver: SourcePathResolver;
234239
_sourceContainer: SourceContainer;
235240
_threadManager: ThreadManager;
236241
_disposables: Disposable[] = [];
237242
_perThread = new Map<string, Map<Cdp.Debugger.BreakpointId, Breakpoint>>();
238243

239-
constructor(dap: Dap.Api, sourcePathResolver: SourcePathResolver, sourceContainer: SourceContainer, threadManager: ThreadManager) {
244+
constructor(dap: Dap.Api, sourceContainer: SourceContainer, threadManager: ThreadManager) {
240245
this._dap = dap;
241-
this._sourcePathResolver = sourcePathResolver;
242246
this._sourceContainer = sourceContainer;
243247
this._threadManager = threadManager;
244248

src/adapter/debugAdapter.ts

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Dap from '../dap/api';
88
import * as sourceUtils from '../utils/sourceUtils';
99
import { BreakpointManager, generateBreakpointId } from './breakpoints';
1010
import * as errors from './errors';
11-
import { Location, SourceContainer, SourcePathResolver } from './sources';
11+
import { Location, SourceContainer } from './sources';
1212
import { DummyThreadAdapter, ThreadAdapter } from './threadAdapter';
1313
import { ExecutionContext, PauseOnExceptionsState, Thread, ThreadManager, ThreadManagerDelegate } from './threads';
1414
import { VariableStore } from './variables';
@@ -23,7 +23,6 @@ export type SetBreakpointRequest = {
2323
};
2424

2525
export interface DebugAdapterDelegate extends ThreadManagerDelegate {
26-
sourcePathResolverFactory: () => SourcePathResolver;
2726
adapterDisposed: () => void;
2827
}
2928

@@ -190,10 +189,9 @@ export class DebugAdapter {
190189

191190
async launch(delegate: DebugAdapterDelegate): Promise<void> {
192191
this._delegate = delegate;
193-
const sourcePathResolver = delegate.sourcePathResolverFactory();
194-
this._sourceContainer = new SourceContainer(this._dap, sourcePathResolver);
195-
this._threadManager = new ThreadManager(this._dap, sourcePathResolver, this._sourceContainer, delegate);
196-
this._breakpointManager = new BreakpointManager(this._dap, sourcePathResolver, this._sourceContainer, this._threadManager);
192+
this._sourceContainer = new SourceContainer(this._dap);
193+
this._threadManager = new ThreadManager(this._dap, this._sourceContainer, delegate);
194+
this._breakpointManager = new BreakpointManager(this._dap, this._sourceContainer, this._threadManager);
197195

198196
await this._threadManager.setPauseOnExceptionsState(this._pausedOnExceptionsState);
199197
for (const request of this._setBreakpointRequests)

src/adapter/sources.ts

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ export interface SourcePathResolver {
9090
//
9191
export class Source {
9292
private static _lastSourceReference = 0;
93-
93+
_sourcePathResolver: SourcePathResolver;
9494
_sourceReference: number;
9595
_url: string;
9696
_name: string;
@@ -120,16 +120,17 @@ export class Source {
120120

121121
private _content?: Promise<string | undefined>;
122122

123-
constructor(container: SourceContainer, url: string, contentGetter: ContentGetter, sourceMapUrl?: string, inlineScriptOffset?: InlineScriptOffset, contentHash?: string) {
123+
constructor(container: SourceContainer, sourcePathResolver: SourcePathResolver, url: string, contentGetter: ContentGetter, sourceMapUrl?: string, inlineScriptOffset?: InlineScriptOffset, contentHash?: string) {
124124
this._sourceReference = ++Source._lastSourceReference;
125+
this._sourcePathResolver = sourcePathResolver;
125126
this._url = url;
126127
this._contentGetter = contentGetter;
127128
this._sourceMapUrl = sourceMapUrl;
128129
this._inlineScriptOffset = inlineScriptOffset;
129130
this._container = container;
130131
this._fqname = this._fullyQualifiedName();
131132
this._name = path.basename(this._fqname);
132-
this._absolutePath = container._sourcePathResolver.urlToAbsolutePath(url);
133+
this._absolutePath = sourcePathResolver.urlToAbsolutePath(url);
133134

134135
// Inline scripts will never match content of the html file. We skip the content check.
135136
if (inlineScriptOffset)
@@ -246,7 +247,6 @@ export class Source {
246247

247248
export class SourceContainer {
248249
private _dap: Dap.Api;
249-
_sourcePathResolver: SourcePathResolver;
250250
_brokenSourceMapReported = false;
251251

252252
private _sourceByReference: Map<number, Source> = new Map();
@@ -260,9 +260,8 @@ export class SourceContainer {
260260

261261
_fileContentOverrides = new Map<string, string>();
262262

263-
constructor(dap: Dap.Api, sourcePathResolver: SourcePathResolver) {
263+
constructor(dap: Dap.Api) {
264264
this._dap = dap;
265-
this._sourcePathResolver = sourcePathResolver;
266265
}
267266

268267
setSourceMapTimeouts(sourceMapTimeouts: SourceMapTimeouts) {
@@ -403,8 +402,8 @@ export class SourceContainer {
403402
}
404403
}
405404

406-
addSource(url: string, contentGetter: ContentGetter, sourceMapUrl?: string, inlineSourceRange?: InlineScriptOffset, contentHash?: string): Source {
407-
const source = new Source(this, url, contentGetter, sourceMapUrl, inlineSourceRange, contentHash);
405+
addSource(sourcePathResolver: SourcePathResolver, url: string, contentGetter: ContentGetter, sourceMapUrl?: string, inlineSourceRange?: InlineScriptOffset, contentHash?: string): Source {
406+
const source = new Source(this, sourcePathResolver, url, contentGetter, sourceMapUrl, inlineSourceRange, contentHash);
408407
this._addSource(source);
409408
return source;
410409
}
@@ -487,7 +486,7 @@ export class SourceContainer {
487486
compiled._sourceMapSourceByUrl = new Map();
488487
const addedSources: Source[] = [];
489488
for (const url of map.sources) {
490-
const sourceUrl = this._sourcePathResolver.rewriteSourceUrl(url);
489+
const sourceUrl = compiled._sourcePathResolver.rewriteSourceUrl(url);
491490
const baseUrl = sourceMapUrl.startsWith('data:') ? compiled.url() : sourceMapUrl;
492491
const resolvedUrl = utils.completeUrl(baseUrl, sourceUrl) || sourceUrl;
493492
const contentOrNull = map.sourceContentFor(url);
@@ -496,7 +495,7 @@ export class SourceContainer {
496495
const isNew = !source;
497496
if (!source) {
498497
// Note: we can support recursive source maps here if we parse sourceMapUrl comment.
499-
source = new Source(this, resolvedUrl, content !== undefined ? () => Promise.resolve(content) : () => utils.fetch(resolvedUrl));
498+
source = new Source(this, compiled._sourcePathResolver, resolvedUrl, content !== undefined ? () => Promise.resolve(content) : () => utils.fetch(resolvedUrl));
500499
source._compiledToSourceUrl = new Map();
501500
}
502501
source._compiledToSourceUrl!.set(compiled, url);

src/adapter/threads.ts

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -45,16 +45,18 @@ export interface ExecutionContext {
4545

4646
export type Script = { scriptId: string, hash: string, source: Source, thread: Thread };
4747

48-
export interface ThreadConfiguration {
49-
supportsCustomBreakpoints?: boolean;
50-
defaultScriptOffset?: InlineScriptOffset;
51-
}
52-
5348
export interface ThreadManagerDelegate {
54-
copyToClipboard(text: string): void;
5549
executionContextForest(): ExecutionContext[] | undefined;
56-
canStopThread(thread: Thread): boolean;
57-
stopThread(thread: Thread): void;
50+
copyToClipboard: (text: string) => void;
51+
}
52+
53+
export interface ThreadDelegate {
54+
canStopThread(): boolean;
55+
stopThread(): void;
56+
57+
supportsCustomBreakpoints?: boolean;
58+
defaultScriptOffset?: InlineScriptOffset;
59+
sourcePathResolver: SourcePathResolver;
5860
}
5961

6062
export type ScriptWithSourceMapHandler = (script: Script, sources: Source[]) => Promise<void>;
@@ -76,17 +78,15 @@ export class ThreadManager {
7678
readonly onThreadResumed = this._onThreadResumedEmitter.event;
7779
readonly onExecutionContextsChanged = this._onExecutionContextsChangedEmitter.event;
7880
readonly sourceContainer: SourceContainer;
79-
_sourcePathResolver: SourcePathResolver;
8081
_delegate: ThreadManagerDelegate;
8182
_scriptWithSourceMapHandler?: ScriptWithSourceMapHandler;
8283
_consoleIsDirty = false;
8384

8485
// url => (hash => Source)
8586
private _scriptSources = new Map<string, Map<string, Source>>();
8687

87-
constructor(dap: Dap.Api, sourcePathResolver: SourcePathResolver, sourceContainer: SourceContainer, delegate: ThreadManagerDelegate) {
88+
constructor(dap: Dap.Api, sourceContainer: SourceContainer, delegate: ThreadManagerDelegate) {
8889
this._dap = dap;
89-
this._sourcePathResolver = sourcePathResolver;
9090
this._pauseOnExceptionsState = 'none';
9191
this._customBreakpoints = new Set();
9292
this.sourceContainer = sourceContainer;
@@ -97,8 +97,8 @@ export class ThreadManager {
9797
return this._threads.values().next().value;
9898
}
9999

100-
createThread(threadId: string, cdp: Cdp.Api, configuration: ThreadConfiguration): Thread {
101-
return new Thread(this, threadId, cdp, this._dap, configuration);
100+
createThread(threadId: string, cdp: Cdp.Api, delegate: ThreadDelegate): Thread {
101+
return new Thread(this, threadId, cdp, this._dap, delegate);
102102
}
103103

104104
setScriptSourceMapHandler(handler?: ScriptWithSourceMapHandler) {
@@ -208,27 +208,27 @@ export class Thread implements VariableStoreDelegate {
208208
private _pausedVariables?: VariableStore;
209209
private _pausedForSourceMapScriptId?: string;
210210
private _scripts: Map<string, Script> = new Map();
211-
private _supportsCustomBreakpoints: boolean;
212-
private _defaultScriptOffset?: InlineScriptOffset;
211+
private _delegate: ThreadDelegate;
213212
private _executionContexts: Map<number, Cdp.Runtime.ExecutionContextDescription> = new Map();
214213
readonly replVariables: VariableStore;
215214
readonly manager: ThreadManager;
216215
readonly sourceContainer: SourceContainer;
216+
readonly sourcePathResolver: SourcePathResolver;
217217
readonly threadLog = new ThreadLog();
218218
private _eventListeners: eventUtils.Listener[] = [];
219219
private _supportsSourceMapPause = false;
220220
private _serializedOutput: Promise<void>;
221221
_debuggerId?: Cdp.Runtime.UniqueDebuggerId;
222222

223-
constructor(manager: ThreadManager, threadId: string, cdp: Cdp.Api, dap: Dap.Api, configuration: ThreadConfiguration) {
223+
constructor(manager: ThreadManager, threadId: string, cdp: Cdp.Api, dap: Dap.Api, delegate: ThreadDelegate) {
224224
this.manager = manager;
225225
this.sourceContainer = manager.sourceContainer;
226+
this.sourcePathResolver = delegate.sourcePathResolver;
226227
this._cdp = cdp;
227228
this._dap = dap;
228229
this._threadId = threadId;
229230
this._name = '';
230-
this._supportsCustomBreakpoints = configuration.supportsCustomBreakpoints || false;
231-
this._defaultScriptOffset = configuration.defaultScriptOffset;
231+
this._delegate = delegate;
232232
this.replVariables = new VariableStore(this._cdp, this);
233233
this.manager._addThread(this);
234234
this._serializedOutput = Promise.resolve();
@@ -302,11 +302,11 @@ export class Thread implements VariableStoreDelegate {
302302
}
303303

304304
canStop(): boolean {
305-
return this.manager._delegate.canStopThread(this);
305+
return this._delegate.canStopThread();
306306
}
307307

308308
stop() {
309-
this.manager._delegate.stopThread(this);
309+
this._delegate.stopThread();
310310
}
311311

312312
initialize() {
@@ -482,10 +482,10 @@ export class Thread implements VariableStoreDelegate {
482482
const script = rawLocation.scriptId ? this._scripts.get(rawLocation.scriptId) : undefined;
483483
let {lineNumber, columnNumber} = rawLocation;
484484
columnNumber = columnNumber || 0;
485-
if (this._defaultScriptOffset) {
486-
lineNumber -= this._defaultScriptOffset.lineOffset;
485+
if (this._delegate.defaultScriptOffset) {
486+
lineNumber -= this._delegate.defaultScriptOffset.lineOffset;
487487
if (!lineNumber)
488-
columnNumber = Math.max(columnNumber - this._defaultScriptOffset.columnOffset, 0);
488+
columnNumber = Math.max(columnNumber - this._delegate.defaultScriptOffset.columnOffset, 0);
489489
}
490490
// Note: cdp locations are 0-based, while ui locations are 1-based.
491491
return this.sourceContainer.preferredLocation({
@@ -509,7 +509,7 @@ export class Thread implements VariableStoreDelegate {
509509
async updateCustomBreakpoint(id: CustomBreakpointId, enabled: boolean): Promise<boolean> {
510510
// Do not fail for custom breakpoints, to account for
511511
// future changes in cdp vs stale breakpoints saved in the workspace.
512-
if (!this._supportsCustomBreakpoints)
512+
if (!this._delegate.supportsCustomBreakpoints)
513513
return true;
514514
const breakpoint = customBreakpoints().get(id);
515515
if (!breakpoint)
@@ -703,7 +703,7 @@ export class Thread implements VariableStoreDelegate {
703703
}
704704

705705
_onScriptParsed(event: Cdp.Debugger.ScriptParsedEvent) {
706-
event.url = this.manager._sourcePathResolver.scriptUrlToUrl(event.url);
706+
event.url = this.sourcePathResolver.scriptUrlToUrl(event.url);
707707

708708
let source: Source | undefined;
709709
if (event.url && event.hash)
@@ -727,7 +727,7 @@ export class Thread implements VariableStoreDelegate {
727727
errors.reportToConsole(this._dap, `Could not load source map from ${event.sourceMapURL}`);
728728
}
729729

730-
source = this.sourceContainer.addSource(event.url, contentGetter, resolvedSourceMapUrl, inlineSourceOffset, event.hash);
730+
source = this.sourceContainer.addSource(this.sourcePathResolver, event.url, contentGetter, resolvedSourceMapUrl, inlineSourceOffset, event.hash);
731731
this.manager._addSourceForScript(event.url, event.hash, source);
732732
}
733733

src/chrome/chromeAdapter.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ import * as utils from '../utils/urlUtils';
1616
import findChrome from './findChrome';
1717
import * as launcher from './launcher';
1818
import { Target, TargetManager } from './targets';
19-
import { Thread } from '../adapter/threads';
2019

2120
const localize = nls.loadMessageBundle();
2221

@@ -100,15 +99,13 @@ export class ChromeAdapter {
10099
this._launchParams = params;
101100

102101
await this._debugAdapter.launch({
103-
sourcePathResolverFactory: () => new ChromeSourcePathResolver(this._rootPath, params.url, params.webRoot),
104-
executionContextForest: () => this._targetManager.executionContextForest(),
105102
adapterDisposed: () => this._dispose(),
106103
copyToClipboard: (text: string) => vscode.env.clipboard.writeText(text),
107-
canStopThread: (thread: Thread) => this._targetManager.canStop(thread.threadId()),
108-
stopThread: (thread: Thread) => this._targetManager.stop(thread.threadId())
104+
executionContextForest: () => this.targetManager().executionContextForest()
109105
});
110106
this._debugAdapter[ChromeAdapter.symbol] = this;
111-
this._targetManager = new TargetManager(this._connection, this._debugAdapter.threadManager());
107+
const pathResolver = new ChromeSourcePathResolver(this._rootPath, params.url, params.webRoot);
108+
this._targetManager = new TargetManager(this._connection, this._debugAdapter.threadManager(), pathResolver);
112109
this._disposables.push(this._targetManager);
113110

114111
// Note: assuming first page is our main target breaks multiple debugging sessions

src/chrome/targets.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { URL } from 'url';
1111
import { Thread, ThreadManager, ExecutionContext } from '../adapter/threads';
1212
import { FrameModel, Frame } from './frames';
1313
import { ServiceWorkerModel } from './serviceWorkers';
14+
import { SourcePathResolver } from '../adapter/sources';
1415

1516
const debugTarget = debug('target');
1617

@@ -23,15 +24,17 @@ export class TargetManager implements vscode.Disposable {
2324
readonly frameModel = new FrameModel();
2425
readonly serviceWorkerModel = new ServiceWorkerModel(this.frameModel);
2526
_threadManager: ThreadManager;
27+
_sourcePathResolver: SourcePathResolver;
2628

2729
private _onTargetAddedEmitter = new vscode.EventEmitter<Target>();
2830
private _onTargetRemovedEmitter = new vscode.EventEmitter<Target>();
2931
readonly onTargetAdded = this._onTargetAddedEmitter.event;
3032
readonly onTargetRemoved = this._onTargetRemovedEmitter.event;
3133

32-
constructor(connection: CdpConnection, threadManager: ThreadManager) {
34+
constructor(connection: CdpConnection, threadManager: ThreadManager, sourcePathResolver: SourcePathResolver) {
3335
this._connection = connection;
3436
this._threadManager = threadManager;
37+
this._sourcePathResolver = sourcePathResolver;
3538
this._browser = connection.browser();
3639
this._browser.Target.on('targetInfoChanged', event => {
3740
this._targetInfoChanged(event.targetInfo);
@@ -275,7 +278,12 @@ export class Target {
275278
this._manager = targetManager;
276279
this.parentTarget = parentTarget;
277280
if (jsTypes.has(targetInfo.type))
278-
this._thread = targetManager._threadManager.createThread(targetInfo.targetId, cdp, { supportsCustomBreakpoints: domDebuggerTypes.has(targetInfo.type) });
281+
this._thread = targetManager._threadManager.createThread(targetInfo.targetId, cdp, {
282+
canStopThread: () => targetManager.canStop(this._thread!.threadId()),
283+
stopThread: () => targetManager.stop(this._thread!.threadId()),
284+
supportsCustomBreakpoints: domDebuggerTypes.has(targetInfo.type),
285+
sourcePathResolver: this._manager._sourcePathResolver
286+
});
279287
this._updateFromInfo(targetInfo);
280288
this._ondispose = ondispose;
281289
}

0 commit comments

Comments
 (0)