| 16 | payload: SourceMapV3, client: T) => SourceMap; |
| 17 | |
| 18 | export class SourceMapManager<T extends FrameAssociated> extends Common.ObjectWrapper.ObjectWrapper<EventTypes<T>> { |
| 19 | readonly #target: Target; |
| 20 | readonly #factory: SourceMapFactory<T>; |
| 21 | #isEnabled = true; |
| 22 | readonly #clientData = new Map<T, ClientData>(); |
| 23 | readonly #sourceMaps = new Map<SourceMap, T>(); |
| 24 | #attachingClient: T|null = null; |
| 25 | readonly #sourceMapCache = SourceMapCache.create(); |
| 26 | |
| 27 | constructor(target: Target, factory?: SourceMapFactory<T>) { |
| 28 | super(); |
| 29 | |
| 30 | this.#target = target; |
| 31 | this.#factory = |
| 32 | factory ?? ((compiledURL, sourceMappingURL, payload) => new SourceMap(compiledURL, sourceMappingURL, payload)); |
| 33 | } |
| 34 | |
| 35 | setEnabled(isEnabled: boolean): void { |
| 36 | if (isEnabled === this.#isEnabled) { |
| 37 | return; |
| 38 | } |
| 39 | |
| 40 | // We need this copy, because `this.#clientData` is getting modified |
| 41 | // in the loop body and trying to iterate over it at the same time |
| 42 | // leads to an infinite loop. |
| 43 | const clientData = [...this.#clientData.entries()]; |
| 44 | for (const [client] of clientData) { |
| 45 | this.detachSourceMap(client); |
| 46 | } |
| 47 | this.#isEnabled = isEnabled; |
| 48 | for (const [client, {relativeSourceURL, relativeSourceMapURL}] of clientData) { |
| 49 | this.attachSourceMap(client, relativeSourceURL, relativeSourceMapURL); |
| 50 | } |
| 51 | } |
| 52 | |
| 53 | private static getBaseUrl(target: Target|null): Platform.DevToolsPath.UrlString { |
| 54 | while (target && target.type() !== Type.FRAME) { |
| 55 | target = target.parentTarget(); |
| 56 | } |
| 57 | return target?.inspectedURL() ?? Platform.DevToolsPath.EmptyUrlString; |
| 58 | } |
| 59 | |
| 60 | static resolveRelativeSourceURL(target: Target|null, url: Platform.DevToolsPath.UrlString): |
| 61 | Platform.DevToolsPath.UrlString { |
| 62 | url = Common.ParsedURL.ParsedURL.completeURL(SourceMapManager.getBaseUrl(target), url) ?? url; |
| 63 | return url; |
| 64 | } |
| 65 | |
| 66 | sourceMapForClient(client: T): SourceMap|undefined { |
| 67 | return this.#clientData.get(client)?.sourceMap; |
| 68 | } |
| 69 | |
| 70 | // This method actively awaits the source map, if still loading. |
| 71 | sourceMapForClientPromise(client: T): Promise<SourceMap|undefined> { |
| 72 | const clientData = this.#clientData.get(client); |
| 73 | if (!clientData) { |
| 74 | return Promise.resolve(undefined); |
| 75 | } |