diff options
Diffstat (limited to 'devtools/client/shared/source-map-loader/index.js')
-rw-r--r-- | devtools/client/shared/source-map-loader/index.js | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/devtools/client/shared/source-map-loader/index.js b/devtools/client/shared/source-map-loader/index.js new file mode 100644 index 0000000000..ccdb86520f --- /dev/null +++ b/devtools/client/shared/source-map-loader/index.js @@ -0,0 +1,139 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */ + +"use strict"; + +const { + WorkerDispatcher, +} = require("resource://devtools/client/shared/worker-utils.js"); +const EventEmitter = require("resource://devtools/shared/event-emitter.js"); +const { LocalizationHelper } = require("resource://devtools/shared/l10n.js"); + +const L10N = new LocalizationHelper( + "devtools/client/locales/toolbox.properties" +); + +const SOURCE_MAP_WORKER_URL = + "resource://devtools/client/shared/source-map-loader/worker.js"; + +const { + originalToGeneratedId, + generatedToOriginalId, + isGeneratedId, + isOriginalId, +} = require("resource://devtools/client/shared/source-map-loader/utils/index.js"); + +class SourceMapLoader extends WorkerDispatcher { + constructor(targetCommand) { + super(SOURCE_MAP_WORKER_URL); + this.#targetCommand = targetCommand; + } + + #setSourceMapForGeneratedSources = this.task( + "setSourceMapForGeneratedSources" + ); + #getOriginalURLs = this.task("getOriginalURLs"); + #getOriginalSourceText = this.task("getOriginalSourceText"); + #targetCommand = null; + + async getOriginalURLs(urlInfo) { + try { + return await this.#getOriginalURLs(urlInfo); + } catch (error) { + // Note that tests may not pass the targetCommand + if (this.#targetCommand) { + // Catch all errors and log them to the Web Console for users to see. + const message = L10N.getFormatStr( + "toolbox.sourceMapFailure", + error, + urlInfo.url, + urlInfo.sourceMapURL + ); + this.#targetCommand.targetFront.logWarningInPage(message, "source map"); + } + + // And re-throw the error so that the debugger can also interpret the error + throw error; + } + } + + hasOriginalURL = this.task("hasOriginalURL"); + getOriginalRanges = this.task("getOriginalRanges"); + + getGeneratedRanges = this.task("getGeneratedRanges", { + queue: true, + }); + getGeneratedLocation = this.task("getGeneratedLocation", { + queue: true, + }); + getOriginalLocation = this.task("getOriginalLocation", { + queue: true, + }); + + getOriginalLocations = this.task("getOriginalLocations"); + getGeneratedRangesForOriginal = this.task("getGeneratedRangesForOriginal"); + getFileGeneratedRange = this.task("getFileGeneratedRange"); + loadSourceMap = this.task("loadSourceMap"); + + async getOriginalSourceText(originalSourceId) { + try { + return await this.#getOriginalSourceText(originalSourceId); + } catch (error) { + const message = L10N.getFormatStr( + "toolbox.sourceMapSourceFailure", + error.message, + error.metadata ? error.metadata.url : "<unknown>" + ); + + // Note that tests may not pass the targetCommand + if (this.#targetCommand) { + // Catch all errors and log them to the Web Console for users to see. + this.#targetCommand.targetFront.logWarningInPage(message, "source map"); + } + + // Also replace the result with the error text. + // Note that this result has to have the same form + // as whatever the upstream getOriginalSourceText + // returns. + return { + text: message, + contentType: "text/plain", + }; + } + } + + clearSourceMaps = this.task("clearSourceMaps"); + getOriginalStackFrames = this.task("getOriginalStackFrames"); + + async setSourceMapForGeneratedSources(generatedIds, sourceMap) { + const rv = await this.#setSourceMapForGeneratedSources( + generatedIds, + sourceMap + ); + + // Notify and ensure waiting for the SourceMapURLService to process the source map before resolving. + // Otherwise tests start failing because of pending request made by this component. + await this.emitAsync("source-map-created", generatedIds); + + return rv; + } + + destroy() { + // Request to stop the underlying DOM Worker + this.stop(); + // Unregister all listeners + this.clearEvents(); + // SourceMapLoader may be leaked and so it is important to clear most outer references + this.#targetCommand = null; + } +} +EventEmitter.decorate(SourceMapLoader.prototype); + +module.exports = { + SourceMapLoader, + originalToGeneratedId, + generatedToOriginalId, + isGeneratedId, + isOriginalId, +}; |