vscode-chrome-debug-core
Version:
A library for building VS Code debug adapters for targets that support the Chrome Remote Debug Protocol
161 lines (159 loc) • 8.19 kB
JavaScript
;
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const url = require("url");
const vscode_debugadapter_1 = require("vscode-debugadapter");
const chromeUtils = require("../chrome/chromeUtils");
const utils = require("../utils");
/**
* Resolves a relative path in terms of another file
*/
function resolveRelativeToFile(absPath, relPath) {
return path.resolve(path.dirname(absPath), relPath);
}
exports.resolveRelativeToFile = resolveRelativeToFile;
/**
* Determine an absolute path for the sourceRoot.
*/
function getComputedSourceRoot(sourceRoot, generatedPath, pathMapping = {}) {
let absSourceRoot;
if (sourceRoot) {
if (sourceRoot.startsWith('file:///')) {
// sourceRoot points to a local path like "file:///c:/project/src", make it an absolute path
absSourceRoot = utils.canonicalizeUrl(sourceRoot);
}
else if (utils.isAbsolute(sourceRoot)) {
// sourceRoot is like "/src", should be like http://localhost/src, resolve to a local path using pathMaping.
// If path mappings do not apply (e.g. node), assume that sourceRoot is actually a local absolute path.
// Technically not valid but it's easy to end up with paths like this.
absSourceRoot = chromeUtils.applyPathMappingsToTargetUrlPath(sourceRoot, pathMapping) || sourceRoot;
// If no pathMapping (node), use sourceRoot as is.
// But we also should handle an absolute sourceRoot for chrome? Does CDT handle that? No it does not, it interprets it as "localhost/full path here"
}
else if (path.isAbsolute(generatedPath)) {
// sourceRoot is like "src" or "../src", relative to the script
absSourceRoot = resolveRelativeToFile(generatedPath, sourceRoot);
}
else {
// generatedPath is a URL so runtime script is not on disk, resolve the sourceRoot location on disk.
const generatedUrlPath = url.parse(generatedPath).pathname;
const mappedPath = chromeUtils.applyPathMappingsToTargetUrlPath(generatedUrlPath, pathMapping);
const mappedDirname = path.dirname(mappedPath);
absSourceRoot = path.join(mappedDirname, sourceRoot);
}
vscode_debugadapter_1.logger.log(`SourceMap: resolved sourceRoot ${sourceRoot} -> ${absSourceRoot}`);
}
else if (path.isAbsolute(generatedPath)) {
absSourceRoot = path.dirname(generatedPath);
vscode_debugadapter_1.logger.log(`SourceMap: no sourceRoot specified, using script dirname: ${absSourceRoot}`);
}
else {
// No sourceRoot and runtime script is not on disk, resolve the sourceRoot location on disk
const urlPathname = url.parse(generatedPath).pathname || '/placeholder.js'; // could be debugadapter://123, no other info.
const mappedPath = chromeUtils.applyPathMappingsToTargetUrlPath(urlPathname, pathMapping);
const scriptPathDirname = mappedPath ? path.dirname(mappedPath) : '';
absSourceRoot = scriptPathDirname;
vscode_debugadapter_1.logger.log(`SourceMap: no sourceRoot specified, using webRoot + script path dirname: ${absSourceRoot}`);
}
absSourceRoot = utils.stripTrailingSlash(absSourceRoot);
absSourceRoot = utils.fixDriveLetterAndSlashes(absSourceRoot);
return absSourceRoot;
}
exports.getComputedSourceRoot = getComputedSourceRoot;
let aspNetFallbackCount = 0;
function getAspNetFallbackCount() {
return aspNetFallbackCount;
}
exports.getAspNetFallbackCount = getAspNetFallbackCount;
/**
* Applies a set of path pattern mappings to the given path. See tests for examples.
* Returns something validated to be an absolute path.
*/
function applySourceMapPathOverrides(sourcePath, sourceMapPathOverrides, isVSClient = false) {
const forwardSlashSourcePath = sourcePath.replace(/\\/g, '/');
// Sort the overrides by length, large to small
const sortedOverrideKeys = Object.keys(sourceMapPathOverrides)
.sort((a, b) => b.length - a.length);
// Iterate the key/vals, only apply the first one that matches.
for (let leftPattern of sortedOverrideKeys) {
const rightPattern = sourceMapPathOverrides[leftPattern];
const entryStr = `"${leftPattern}": "${rightPattern}"`;
const asterisks = leftPattern.match(/\*/g) || [];
if (asterisks.length > 1) {
vscode_debugadapter_1.logger.log(`Warning: only one asterisk allowed in a sourceMapPathOverrides entry - ${entryStr}`);
continue;
}
const replacePatternAsterisks = rightPattern.match(/\*/g) || [];
if (replacePatternAsterisks.length > asterisks.length) {
vscode_debugadapter_1.logger.log(`Warning: the right side of a sourceMapPathOverrides entry must have 0 or 1 asterisks - ${entryStr}}`);
continue;
}
// Does it match?
const escapedLeftPattern = utils.escapeRegexSpecialChars(leftPattern, '/*');
const leftRegexSegment = escapedLeftPattern
.replace(/\*/g, '(.*)')
.replace(/\\\\/g, '/');
const leftRegex = new RegExp(`^${leftRegexSegment}$`, 'i');
const overridePatternMatches = forwardSlashSourcePath.match(leftRegex);
if (!overridePatternMatches)
continue;
// Grab the value of the wildcard from the match above, replace the wildcard in the
// replacement pattern, and return the result.
const wildcardValue = overridePatternMatches[1];
let mappedPath = rightPattern.replace(/\*/g, wildcardValue);
mappedPath = path.join(mappedPath); // Fix any ..
if (isVSClient && leftPattern === 'webpack:///./*' && !utils.existsSync(mappedPath)) {
// This is a workaround for a bug in ASP.NET debugging in VisualStudio because the wwwroot is not properly configured
const pathFixingASPNETBug = path.join(rightPattern.replace(/\*/g, path.join('../ClientApp', wildcardValue)));
if (utils.existsSync(pathFixingASPNETBug)) {
++aspNetFallbackCount;
mappedPath = pathFixingASPNETBug;
}
}
vscode_debugadapter_1.logger.log(`SourceMap: mapping ${sourcePath} => ${mappedPath}, via sourceMapPathOverrides entry - ${entryStr}`);
return mappedPath;
}
return sourcePath;
}
exports.applySourceMapPathOverrides = applySourceMapPathOverrides;
function resolveMapPath(pathToGenerated, mapPath, pathMapping) {
if (!utils.isURL(mapPath)) {
if (utils.isURL(pathToGenerated)) {
const scriptUrl = url.parse(pathToGenerated);
const scriptPath = scriptUrl.pathname;
if (!scriptPath) {
return null;
}
// runtime script is not on disk, map won't be either, resolve a URL for the map relative to the script
// handle c:/ here too
const mapUrlPathSegment = utils.isAbsolute(mapPath) ?
mapPath :
path.posix.join(path.dirname(scriptPath), mapPath);
mapPath = `${scriptUrl.protocol}//${scriptUrl.host}${mapUrlPathSegment}`;
}
else if (utils.isAbsolute(mapPath)) {
mapPath = chromeUtils.applyPathMappingsToTargetUrlPath(mapPath, pathMapping) || mapPath;
}
else if (path.isAbsolute(pathToGenerated)) {
// mapPath needs to be resolved to an absolute path or a URL
// runtime script is on disk, so map should be too
mapPath = resolveRelativeToFile(pathToGenerated, mapPath);
}
}
return mapPath;
}
exports.resolveMapPath = resolveMapPath;
function getFullSourceEntry(sourceRoot, sourcePath) {
if (!sourceRoot) {
return sourcePath;
}
if (!sourceRoot.endsWith('/')) {
sourceRoot += '/';
}
return sourceRoot + sourcePath;
}
exports.getFullSourceEntry = getFullSourceEntry;
//# sourceMappingURL=sourceMapUtils.js.map