vscode-chrome-debug-core
Version:
A library for building VS Code debug adapters for targets that support the Chrome Remote Debug Protocol
206 lines (204 loc) • 9.59 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 vscode_debugadapter_1 = require("vscode-debugadapter");
const utils = require("../utils");
class ScriptSkipper {
constructor(_chromeConnection, _transformers) {
this._chromeConnection = _chromeConnection;
this._transformers = _transformers;
this._skipFileStatuses = new Map();
this._blackboxedRegexes = [];
}
get chrome() { return this._chromeConnection.api; }
init(skipFiles, skipFileRegExps) {
let patterns = [];
if (skipFiles) {
const skipFilesArgs = skipFiles.filter(glob => {
if (glob.startsWith('!')) {
vscode_debugadapter_1.logger.warn(`Warning: skipFiles entries starting with '!' aren't supported and will be ignored. ("${glob}")`);
return false;
}
return true;
});
patterns = skipFilesArgs.map(glob => utils.pathGlobToBlackboxedRegex(glob));
}
if (skipFileRegExps) {
patterns = patterns.concat(skipFileRegExps);
}
if (patterns.length) {
this._blackboxedRegexes = patterns.map(pattern => new RegExp(pattern, 'i'));
this.refreshBlackboxPatterns();
}
}
toggleSkipFileStatus(args, scripts, transformers) {
return __awaiter(this, void 0, void 0, function* () {
// e.g. strip <node_internals>/
if (args.path) {
args.path = scripts.displayPathToRealPath(args.path);
}
const aPath = args.path || scripts.fakeUrlForSourceReference(args.sourceReference);
const generatedPath = yield transformers.sourceMapTransformer.getGeneratedPathFromAuthoredPath(aPath);
if (!generatedPath) {
vscode_debugadapter_1.logger.log(`Can't toggle the skipFile status for: ${aPath} - haven't seen it yet.`);
return;
}
const sources = yield transformers.sourceMapTransformer.allSources(generatedPath);
if (generatedPath === aPath && sources.length) {
// Ignore toggling skip status for generated scripts with sources
vscode_debugadapter_1.logger.log(`Can't toggle skipFile status for ${aPath} - it's a script with a sourcemap`);
return;
}
const newStatus = !this.shouldSkipSource(aPath);
vscode_debugadapter_1.logger.log(`Setting the skip file status for: ${aPath} to ${newStatus}`);
this._skipFileStatuses.set(aPath, newStatus);
const targetPath = transformers.pathTransformer.getTargetPathFromClientPath(generatedPath) || generatedPath;
const script = scripts.getScriptByUrl(targetPath);
yield this.resolveSkipFiles(script, generatedPath, sources, /*toggling=*/ true);
if (newStatus) {
this.makeRegexesSkip(script.url);
}
else {
this.makeRegexesNotSkip(script.url);
}
});
}
resolveSkipFiles(script, mappedUrl, sources, toggling) {
return __awaiter(this, void 0, void 0, function* () {
if (sources && sources.length) {
const parentIsSkipped = this.shouldSkipSource(script.url);
const libPositions = [];
// Figure out skip/noskip transitions within script
let inLibRange = parentIsSkipped;
for (let s of sources) {
let isSkippedFile = this.shouldSkipSource(s);
if (typeof isSkippedFile !== 'boolean') {
// Inherit the parent's status
isSkippedFile = parentIsSkipped;
}
this._skipFileStatuses.set(s, isSkippedFile);
if ((isSkippedFile && !inLibRange) || (!isSkippedFile && inLibRange)) {
const details = yield this._transformers.sourceMapTransformer.allSourcePathDetails(mappedUrl);
const detail = details.find(d => d.inferredPath === s);
if (detail.startPosition) {
libPositions.push({
lineNumber: detail.startPosition.line,
columnNumber: detail.startPosition.column
});
}
inLibRange = !inLibRange;
}
}
// If there's any change from the default, set proper blackboxed ranges
if (libPositions.length || toggling) {
if (parentIsSkipped) {
libPositions.splice(0, 0, { lineNumber: 0, columnNumber: 0 });
}
if (libPositions[0].lineNumber !== 0 || libPositions[0].columnNumber !== 0) {
// The list of blackboxed ranges must start with 0,0 for some reason.
// https://github.com/Microsoft/vscode-chrome-debug/issues/667
libPositions[0] = {
lineNumber: 0,
columnNumber: 0
};
}
yield this.chrome.Debugger.setBlackboxedRanges({
scriptId: script.scriptId,
positions: []
}).catch(() => this.warnNoSkipFiles());
if (libPositions.length) {
this.chrome.Debugger.setBlackboxedRanges({
scriptId: script.scriptId,
positions: libPositions
}).catch(() => this.warnNoSkipFiles());
}
}
}
else {
const status = yield this.getSkipStatus(mappedUrl);
const skippedByPattern = this.matchesSkipFilesPatterns(mappedUrl);
if (typeof status === 'boolean' && status !== skippedByPattern) {
const positions = status ? [{ lineNumber: 0, columnNumber: 0 }] : [];
this.chrome.Debugger.setBlackboxedRanges({
scriptId: script.scriptId,
positions
}).catch(() => this.warnNoSkipFiles());
}
}
});
}
makeRegexesNotSkip(noSkipPath) {
let somethingChanged = false;
this._blackboxedRegexes = this._blackboxedRegexes.map(regex => {
const result = utils.makeRegexNotMatchPath(regex, noSkipPath);
somethingChanged = somethingChanged || (result !== regex);
return result;
});
if (somethingChanged) {
this.refreshBlackboxPatterns();
}
}
makeRegexesSkip(skipPath) {
let somethingChanged = false;
this._blackboxedRegexes = this._blackboxedRegexes.map(regex => {
const result = utils.makeRegexMatchPath(regex, skipPath);
somethingChanged = somethingChanged || (result !== regex);
return result;
});
if (!somethingChanged) {
this._blackboxedRegexes.push(new RegExp(utils.pathToRegex(skipPath), 'i'));
}
this.refreshBlackboxPatterns();
}
refreshBlackboxPatterns() {
this.chrome.Debugger.setBlackboxPatterns({
patterns: this._blackboxedRegexes.map(regex => regex.source)
}).catch(() => this.warnNoSkipFiles());
}
/**
* If the source has a saved skip status, return that, whether true or false.
* If not, check it against the patterns list.
*/
shouldSkipSource(sourcePath) {
const status = this.getSkipStatus(sourcePath);
if (typeof status === 'boolean') {
return status;
}
if (this.matchesSkipFilesPatterns(sourcePath)) {
return true;
}
return undefined;
}
/**
* Returns true if this path matches one of the static skip patterns
*/
matchesSkipFilesPatterns(sourcePath) {
return this._blackboxedRegexes.some(regex => {
return regex.test(sourcePath);
});
}
/**
* Returns the current skip status for this path, which is either an authored or generated script.
*/
getSkipStatus(sourcePath) {
if (this._skipFileStatuses.has(sourcePath)) {
return this._skipFileStatuses.get(sourcePath);
}
return undefined;
}
warnNoSkipFiles() {
vscode_debugadapter_1.logger.log('Warning: this runtime does not support skipFiles');
}
}
exports.ScriptSkipper = ScriptSkipper;
//# sourceMappingURL=scriptSkipping.js.map