vscode-chrome-debug-core
Version:
A library for building VS Code debug adapters for targets that support the Chrome Remote Debug Protocol
181 lines (179 loc) • 8.73 kB
JavaScript
;
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const crypto = require("crypto");
const path = require("path");
const os = require("os");
const url = require("url");
const sourceMapUtils = require("./sourceMapUtils");
const utils = require("../utils");
const vscode_debugadapter_1 = require("vscode-debugadapter");
const sourceMap_1 = require("./sourceMap");
const remoteMapper_1 = require("../remoteMapper");
class SourceMapFactory {
constructor(_pathMapping, _sourceMapPathOverrides, _enableSourceMapCaching) {
this._pathMapping = _pathMapping;
this._sourceMapPathOverrides = _sourceMapPathOverrides;
this._enableSourceMapCaching = _enableSourceMapCaching;
}
/**
* pathToGenerated - an absolute local path or a URL.
* mapPath - a path relative to pathToGenerated.
*/
getMapForGeneratedPath(pathToGenerated, originalUrlToGenerated, mapPath, isVSClient = false) {
let msg = `SourceMaps.getMapForGeneratedPath: Finding SourceMap for ${pathToGenerated} by URI: ${mapPath}`;
if (this._pathMapping) {
msg += ` and webRoot/pathMapping: ${JSON.stringify(this._pathMapping)}`;
}
vscode_debugadapter_1.logger.log(msg);
// For an inlined sourcemap, mapPath is a data URI containing a blob of base64 encoded data, starting
// with a tag like "data:application/json;charset:utf-8;base64,". The data should start after the last comma.
let sourceMapContentsP;
if (mapPath.indexOf('data:application/json') >= 0) {
// Sourcemap is inlined
vscode_debugadapter_1.logger.log(`SourceMaps.getMapForGeneratedPath: Using inlined sourcemap in ${pathToGenerated}`);
sourceMapContentsP = Promise.resolve(this.getInlineSourceMapContents(mapPath));
}
else {
const accessPath = remoteMapper_1.isInternalRemotePath(pathToGenerated) && originalUrlToGenerated ?
originalUrlToGenerated :
pathToGenerated;
sourceMapContentsP = this.getSourceMapContent(accessPath, mapPath);
}
return sourceMapContentsP.then(contents => {
if (contents) {
try {
// Throws for invalid JSON
return new sourceMap_1.SourceMap(pathToGenerated, contents, this._pathMapping, this._sourceMapPathOverrides, isVSClient);
}
catch (e) {
vscode_debugadapter_1.logger.error(`SourceMaps.getMapForGeneratedPath: exception while processing path: ${pathToGenerated}, sourcemap: ${mapPath}\n${e.stack}`);
return null;
}
}
else {
return null;
}
});
}
/**
* Parses sourcemap contents from inlined base64-encoded data
*/
getInlineSourceMapContents(sourceMapData) {
const firstCommaPos = sourceMapData.indexOf(',');
if (firstCommaPos < 0) {
vscode_debugadapter_1.logger.log(`SourceMaps.getInlineSourceMapContents: Inline sourcemap is malformed. Starts with: ${sourceMapData.substr(0, 200)}`);
return null;
}
const header = sourceMapData.substr(0, firstCommaPos);
const data = sourceMapData.substr(firstCommaPos + 1);
try {
if (header.indexOf(';base64') !== -1) {
const buffer = Buffer.from(data, 'base64');
return buffer.toString();
}
else {
// URI encoded.
return decodeURI(data);
}
}
catch (e) {
vscode_debugadapter_1.logger.error(`SourceMaps.getInlineSourceMapContents: exception while processing data uri (${e.stack})`);
}
return null;
}
/**
* Resolves a sourcemap's path and loads the data
*/
getSourceMapContent(pathToGenerated, mapPath) {
mapPath = sourceMapUtils.resolveMapPath(pathToGenerated, mapPath, this._pathMapping);
if (!mapPath) {
return Promise.resolve(null);
}
return this.loadSourceMapContents(mapPath).then(contents => {
if (!contents) {
// Last ditch effort - just look for a .js.map next to the script
const mapPathNextToSource = pathToGenerated + '.map';
if (mapPathNextToSource !== mapPath) {
return this.loadSourceMapContents(mapPathNextToSource);
}
}
return contents;
});
}
loadSourceMapContents(mapPathOrURL) {
let contentsP;
if (utils.isURL(mapPathOrURL) && !utils.isFileUrl(mapPathOrURL)) {
vscode_debugadapter_1.logger.log(`SourceMaps.loadSourceMapContents: Downloading sourcemap file from ${mapPathOrURL}`);
contentsP = this.downloadSourceMapContents(mapPathOrURL).catch(e => {
vscode_debugadapter_1.logger.log(`SourceMaps.loadSourceMapContents: Could not download sourcemap from ${mapPathOrURL}`);
return null;
});
}
else {
mapPathOrURL = utils.canonicalizeUrl(mapPathOrURL);
contentsP = new Promise((resolve, reject) => {
vscode_debugadapter_1.logger.log(`SourceMaps.loadSourceMapContents: Reading local sourcemap file from ${mapPathOrURL}`);
fs.readFile(mapPathOrURL, (err, data) => {
if (err) {
vscode_debugadapter_1.logger.log(`SourceMaps.loadSourceMapContents: Could not read sourcemap file - ` + err.message);
resolve(null);
}
else {
resolve(data && data.toString());
}
});
});
}
return contentsP;
}
downloadSourceMapContents(sourceMapUri) {
return __awaiter(this, void 0, void 0, function* () {
try {
return yield this._downloadSourceMapContents(sourceMapUri);
}
catch (e) {
if (url.parse(sourceMapUri).hostname === 'localhost') {
vscode_debugadapter_1.logger.log(`Sourcemaps.downloadSourceMapContents: downlading from 127.0.0.1 instead of localhost`);
return this._downloadSourceMapContents(sourceMapUri.replace('localhost', '127.0.0.1'));
}
throw e;
}
});
}
_downloadSourceMapContents(sourceMapUri) {
return __awaiter(this, void 0, void 0, function* () {
// use sha256 to ensure the hash value can be used in filenames
let cachedSourcemapPath;
if (this._enableSourceMapCaching) {
const hash = crypto.createHash('sha256').update(sourceMapUri).digest('hex');
const cachePath = path.join(os.tmpdir(), 'com.microsoft.VSCode', 'node-debug2', 'sm-cache');
cachedSourcemapPath = path.join(cachePath, hash);
const exists = utils.existsSync(cachedSourcemapPath);
if (exists) {
vscode_debugadapter_1.logger.log(`Sourcemaps.downloadSourceMapContents: Reading cached sourcemap file from ${cachedSourcemapPath}`);
return this.loadSourceMapContents(cachedSourcemapPath);
}
}
const responseText = yield utils.getURL(sourceMapUri);
if (cachedSourcemapPath && this._enableSourceMapCaching) {
vscode_debugadapter_1.logger.log(`Sourcemaps.downloadSourceMapContents: Caching sourcemap file at ${cachedSourcemapPath}`);
yield utils.writeFileP(cachedSourcemapPath, responseText);
}
return responseText;
});
}
}
exports.SourceMapFactory = SourceMapFactory;
//# sourceMappingURL=sourceMapFactory.js.map