Skip to content
This repository was archived by the owner on Dec 6, 2022. It is now read-only.

Commit 9175a28

Browse files
committed
Fix some sourcemap path handling
1 parent 326dd27 commit 9175a28

File tree

10 files changed

+81
-70
lines changed

10 files changed

+81
-70
lines changed

.vscode/launch.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,21 +4,21 @@
44
{
55
"name": "launch as server",
66
"type": "node",
7-
"program": "./out/webkit/webKitDebug.js",
7+
"program": "${workspaceRoot}/out/webkit/webKitDebug.js",
88
"runtimeArgs": ["--harmony"],
99
"stopOnEntry": false,
1010
"args": [ "--server=4712" ],
1111
"sourceMaps": true,
12-
"outDir": "out"
12+
"outDir": "${workspaceRoot}/out"
1313
},
1414
{
1515
"name": "test",
1616
"type": "node",
17-
"program": "./node_modules/gulp/bin/gulp.js",
17+
"program": "${workspaceRoot}/node_modules/gulp/bin/gulp.js",
1818
"stopOnEntry": false,
1919
"args": [ "test" ],
2020
"sourceMaps": true,
21-
"outDir": "out"
21+
"outDir": "${workspaceRoot}/out"
2222
}
2323
]
2424
}

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ When your launch config is set up, you can debug your project! Pick a launch con
103103
General things to try if you're having issues:
104104
* Ensure `webRoot` is set correctly if needed
105105
* If sourcemaps are enabled, try setting `sourceRoot` to be a file URL. `sourceRoot` is a property in the .map file which is usually specified in your project's build config.
106-
* Close other running instances of Chrome - if Chrome is already running, the extension may not be able to attach, when using launch mode. Chrome can even stay running in the background when all its windows are closed, which will interfere.
106+
* Close other running instances of Chrome - if Chrome is already running, the extension may not be able to attach, when using launch mode. Chrome can even stay running in the background when all its windows are closed, which will interfere - check the taskbar or kill the process if necessary.
107107
* Ensure nothing else is using port 9222, or specify a different port in your launch config
108108
* Check the console for warnings that this extension prints in some cases when it can't attach
109109
* Ensure the code in Chrome matches the code in Code. Chrome may cache an old version.

adapter/sourceMaps/sourceMapTransformer.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as path from 'path';
66

77
import {ISourceMaps, SourceMaps} from './sourceMaps';
88
import * as utils from '../../webkit/utilities';
9+
import {Logger} from '../../webkit/utilities';
910

1011
interface IPendingBreakpoint {
1112
resolve: () => void;
@@ -58,7 +59,7 @@ export class SourceMapTransformer implements IDebugTransformer {
5859
const argsPath = args.source.path;
5960
const mappedPath = this._sourceMaps.MapPathFromSource(argsPath);
6061
if (mappedPath) {
61-
utils.Logger.log(`SourceMaps.setBP: Mapped ${argsPath} to ${mappedPath}`);
62+
Logger.log(`SourceMaps.setBP: Mapped ${argsPath} to ${mappedPath}`);
6263
args.authoredPath = argsPath;
6364
args.source.path = mappedPath;
6465

@@ -67,11 +68,11 @@ export class SourceMapTransformer implements IDebugTransformer {
6768
const mappedLines = args.lines.map((line, i) => {
6869
const mapped = this._sourceMaps.MapFromSource(argsPath, line, /*column=*/0);
6970
if (mapped) {
70-
utils.Logger.log(`SourceMaps.setBP: Mapped ${argsPath}:${line}:0 to ${mappedPath}:${mapped.line}:${mapped.column}`);
71+
Logger.log(`SourceMaps.setBP: Mapped ${argsPath}:${line}:0 to ${mappedPath}:${mapped.line}:${mapped.column}`);
7172
mappedCols[i] = mapped.column;
7273
return mapped.line;
7374
} else {
74-
utils.Logger.log(`SourceMaps.setBP: Mapped ${argsPath} but not line ${line}, column 0`);
75+
Logger.log(`SourceMaps.setBP: Mapped ${argsPath} but not line ${line}, column 0`);
7576
mappedCols[i] = 0;
7677
return line;
7778
}
@@ -99,10 +100,10 @@ export class SourceMapTransformer implements IDebugTransformer {
99100
});
100101
} else if (this._allRuntimeScriptPaths.has(argsPath)) {
101102
// It's a generated file which is loaded
102-
utils.Logger.log(`SourceMaps.setBP: SourceMaps are enabled but ${argsPath} is a runtime script`);
103+
Logger.log(`SourceMaps.setBP: SourceMaps are enabled but ${argsPath} is a runtime script`);
103104
} else {
104105
// Source (or generated) file which is not loaded, need to wait
105-
utils.Logger.log(`SourceMaps.setBP: ${argsPath} can't be resolved to a loaded script.`);
106+
Logger.log(`SourceMaps.setBP: ${argsPath} can't be resolved to a loaded script.`);
106107
this._pendingBreakpointsByPath.set(argsPath, { resolve, reject, args, requestSeq });
107108
return;
108109
}
@@ -130,10 +131,10 @@ export class SourceMapTransformer implements IDebugTransformer {
130131
response.breakpoints.forEach(bp => {
131132
const mapped = this._sourceMaps.MapToSource(args.source.path, bp.line, bp.column);
132133
if (mapped) {
133-
utils.Logger.log(`SourceMaps.setBP: Mapped ${args.source.path}:${bp.line}:${bp.column} to ${mapped.path}:${mapped.line}`);
134+
Logger.log(`SourceMaps.setBP: Mapped ${args.source.path}:${bp.line}:${bp.column} to ${mapped.path}:${mapped.line}`);
134135
bp.line = mapped.line;
135136
} else {
136-
utils.Logger.log(`SourceMaps.setBP: Can't map ${args.source.path}:${bp.line}:${bp.column}, keeping the line number as-is.`);
137+
Logger.log(`SourceMaps.setBP: Can't map ${args.source.path}:${bp.line}:${bp.column}, keeping the line number as-is.`);
137138
}
138139

139140
this._requestSeqToSetBreakpointsArgs.delete(requestSeq);
@@ -195,7 +196,7 @@ export class SourceMapTransformer implements IDebugTransformer {
195196
this._sourceMaps.ProcessNewSourceMap(event.body.scriptUrl, event.body.sourceMapURL).then(() => {
196197
const sources = this._sourceMaps.AllMappedSources(event.body.scriptUrl);
197198
if (sources) {
198-
utils.Logger.log(`SourceMaps.scriptParsed: ${event.body.scriptUrl} was just loaded and has mapped sources: ${JSON.stringify(sources) }`);
199+
Logger.log(`SourceMaps.scriptParsed: ${event.body.scriptUrl} was just loaded and has mapped sources: ${JSON.stringify(sources) }`);
199200
sources.forEach(sourcePath => {
200201
this.resolvePendingBreakpointsForScript(sourcePath);
201202
});
@@ -208,9 +209,9 @@ export class SourceMapTransformer implements IDebugTransformer {
208209
* Resolve any pending breakpoints for this script
209210
*/
210211
private resolvePendingBreakpointsForScript(scriptUrl: string): void {
211-
utils.Logger.log(`SourceMaps.scriptParsed: Resolving pending breakpoints for ${scriptUrl}`);
212-
213212
if (this._pendingBreakpointsByPath.has(scriptUrl)) {
213+
Logger.log(`SourceMaps.scriptParsed: Resolving pending breakpoints for ${scriptUrl}`);
214+
214215
let pendingBreakpoints = this._pendingBreakpointsByPath.get(scriptUrl);
215216
this._pendingBreakpointsByPath.delete(scriptUrl);
216217

adapter/sourceMaps/sourceMaps.ts

Lines changed: 24 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -241,11 +241,8 @@ enum Bias {
241241

242242
class SourceMap {
243243
private _generatedPath: string; // the generated file for this sourcemap
244-
private _sources: string[]; // the sources of generated file (relative to sourceRoot)
245-
private _absSourceRoot: string; // the common prefix for the source (can be a URL)
244+
private _sources: string[]; // list of authored files (absolute paths)
246245
private _smc: SourceMapConsumer; // the source map
247-
private _webRoot: string; // if the sourceRoot starts with /, it's resolved from this absolute path
248-
private _sourcesAreURLs: boolean; // if sources are specified with file:///
249246

250247
/**
251248
* pathToGenerated - an absolute local path or a URL
@@ -255,40 +252,39 @@ class SourceMap {
255252
public constructor(generatedPath: string, json: string, webRoot: string) {
256253
Logger.log(`SourceMap: creating SM for ${generatedPath}`)
257254
this._generatedPath = generatedPath;
258-
this._webRoot = webRoot;
259255

260256
const sm = JSON.parse(json);
261-
this._absSourceRoot = PathUtils.getAbsSourceRoot(sm.sourceRoot, this._webRoot, this._generatedPath);
257+
const absSourceRoot = PathUtils.getAbsSourceRoot(sm.sourceRoot, webRoot, this._generatedPath);
262258

263259
// Overwrite the sourcemap's sourceRoot with the version that's resolved to an absolute path,
264260
// so the work above only has to be done once
265-
sm.sourceRoot = utils.pathToFileURL(this._absSourceRoot);
261+
sm.sourceRoot = null; // probably get rid of this._sourceRoot?
266262

267-
sm.sources = sm.sources.map((sourcePath: string) => {
268-
// special-case webpack:/// prefixed sources which is kind of meaningless
263+
// sm.sources are relative paths or file:/// urls - (or other URLs?) read the spec...
264+
// resolve them to file:/// urls, using absSourceRoot.
265+
// note - the source-map library doesn't like backslashes, but some tools output them.
266+
// Which is wrong? Consider filing issues on source-map or tools that output backslashes?
267+
// In either case, support whatever works
268+
this._sources = sm.sources.map((sourcePath: string) => {
269+
// Special-case webpack:/// prefixed sources which is kind of meaningless
269270
sourcePath = utils.lstrip(sourcePath, 'webpack:///');
271+
sourcePath = utils.canonicalizeUrl(sourcePath);
270272

271-
// Force correct format for sanity
272-
return utils.fixDriveLetterAndSlashes(sourcePath);
273-
});
274-
275-
this._smc = new SourceMapConsumer(sm);
276-
277-
// rewrite sources as absolute paths
278-
this._sources = sm.sources.map((sourcePath: string) => {
279-
if (sourcePath.startsWith('file:///')) {
280-
// If one source is a URL, assume all are
281-
this._sourcesAreURLs = true;
273+
// If not already an absolute path, make it an absolute path with this._absSourceRoot. Also resolves '..' parts.
274+
if (!Path.isAbsolute(sourcePath)) {
275+
sourcePath = Path.resolve(absSourceRoot, sourcePath);
282276
}
283277

284-
sourcePath = utils.lstrip(sourcePath, 'webpack:///');
285-
sourcePath = PathUtils.canonicalizeUrl(sourcePath);
286-
if (Path.isAbsolute(sourcePath)) {
287-
return utils.fixDriveLetterAndSlashes(sourcePath);
288-
} else {
289-
return Path.join(this._absSourceRoot, sourcePath);
290-
}
278+
return sourcePath;
279+
});
280+
281+
// Rewrite sm.sources to same as this._sources but forward slashes and file url
282+
sm.sources = this._sources.map(sourceAbsPath => {
283+
// Convert to file: url. After this, it's a file URL for an absolute path to a file on disk with forward slashes.
284+
return utils.pathToFileURL(sourceAbsPath);
291285
});
286+
287+
this._smc = new SourceMapConsumer(sm);
292288
}
293289

294290
/*
@@ -316,7 +312,6 @@ class SourceMap {
316312
* finds the nearest source location for the given location in the generated file.
317313
*/
318314
public originalPositionFor(line: number, column: number, bias: Bias = Bias.GREATEST_LOWER_BOUND): SourceMap.MappedPosition {
319-
320315
const mp = this._smc.originalPositionFor(<any>{
321316
line: line,
322317
column: column,
@@ -334,25 +329,14 @@ class SourceMap {
334329
* finds the nearest location in the generated file for the given source location.
335330
*/
336331
public generatedPositionFor(src: string, line: number, column: number, bias = Bias.GREATEST_LOWER_BOUND): SourceMap.Position {
337-
if (this._sourcesAreURLs) {
338-
src = utils.pathToFileURL(src);
339-
} else if (this._absSourceRoot) {
340-
// make input path relative to sourceRoot
341-
src = Path.relative(this._absSourceRoot, src);
342-
343-
// source-maps use forward slashes unless the source is specified with file:///
344-
if (process.platform === 'win32') {
345-
src = src.replace(/\\/g, '/');
346-
}
347-
}
332+
src = utils.pathToFileURL(src);
348333

349334
const needle = {
350335
source: src,
351336
line: line,
352337
column: column,
353338
bias: bias
354339
};
355-
356340
return this._smc.generatedPositionFor(needle);
357341
}
358342
}

test/webkit/utilities.test.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,11 +435,15 @@ suite('Utilities', () => {
435435

436436
suite('pathToFileURL', () => {
437437
test('converts windows-style paths', () => {
438-
assert.equal(getUtilities().pathToFileURL('c:/code/app.js'), 'file:///c:/code/app.js');
438+
assert.equal(getUtilities().pathToFileURL('c:\\code\\app.js'), 'file:///c:/code/app.js');
439439
});
440440

441441
test('converts unix-style paths', () => {
442442
assert.equal(getUtilities().pathToFileURL('/code/app.js'), 'file:///code/app.js');
443443
});
444+
445+
test('encodes as URI', () => {
446+
assert.equal(getUtilities().pathToFileURL('c:\\path with spaces'), 'file:///c:/path%20with%20spaces');
447+
});
444448
});
445449
});

testapp/.vscode/launch.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"version": "0.1.0",
3-
// "debugServer": "4712",
3+
"debugServer": "4712",
44
"configurations": [
55
{
66
"name": "test chrome",
@@ -9,16 +9,16 @@
99
"url": "http://localhost:8080/index.html",
1010
"sourceMaps": true,
1111
"diagnosticLogging": true,
12-
"webRoot": "wwwroot"
12+
"webRoot": "${workspaceRoot}/wwwroot"
1313
},
1414
{
1515
"name": "launch for file",
1616
"type": "chrome",
1717
"request": "launch",
18-
"file": "wwwroot/index.html",
18+
"file": "${workspaceRoot}/wwwroot/index.html",
1919
"sourceMaps": true,
2020
"diagnosticLogging": true,
21-
"webRoot": "wwwroot/out/client with space"
21+
"webRoot": "${workspaceRoot}/wwwroot/out/client with space"
2222
},
2323
{
2424
"name": "attach to chrome",
@@ -27,7 +27,7 @@
2727
"request": "attach",
2828
"sourceMaps": true,
2929
"diagnosticLogging": true,
30-
"webRoot": "./wwwroot"
30+
"webRoot": "${workspaceRoot}/wwwroot"
3131
}
3232
]
3333
}

testapp/gulpfile.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ var filter = require('gulp-filter');
1414

1515
var sources = [
1616
'wwwroot/client with space'
17-
].map(function (tsFolder) { return tsFolder + '/**/*.ts'; });
17+
].map(function (tsFolder) { return tsFolder + '\\**\\*.ts'; });
1818

1919
var projectConfig = {
2020
target: 'ES6',
@@ -34,7 +34,7 @@ gulp.task('build', function () {
3434
.pipe(gulp.dest('./wwwroot/out'));
3535
});
3636

37-
gulp.task('serve', ['build'], function (done) {
37+
function serve(done) {
3838
browserSync({
3939
online: false,
4040
open: false,
@@ -43,7 +43,10 @@ gulp.task('serve', ['build'], function (done) {
4343
baseDir: ['./wwwroot']
4444
}
4545
}, done);
46-
});
46+
}
47+
48+
gulp.task('serve', serve);
49+
gulp.task('buildAndServe', ['build'], serve);
4750

4851
gulp.task('bs-reload', ['build'], function() {
4952
browserSync.reload();

webkit/utilities.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ export function webkitUrlToClientPath(webRoot: string, aUrl: string): string {
245245
* The client can handle urls in this format too.
246246
* file:///D:\\scripts\\code.js => d:/scripts/code.js
247247
* file:///Users/me/project/code.js => /Users/me/project/code.js
248-
* c:\\scripts\\code.js => c:/scripts/code.js
248+
* c:/scripts/code.js => c:\\scripts\\code.js
249249
* http://site.com/scripts/code.js => (no change)
250250
* http://site.com/ => http://site.com
251251
*/
@@ -263,6 +263,14 @@ export function canonicalizeUrl(aUrl: string): string {
263263
return aUrl;
264264
}
265265

266+
/**
267+
* Replace any backslashes with forward slashes
268+
* blah\something => blah/something
269+
*/
270+
export function forceForwardSlashes(aUrl: string): string {
271+
return aUrl.replace(/\\/g, '/');
272+
}
273+
266274
/**
267275
* Ensure lower case drive letter and \ on Windows
268276
*/
@@ -413,7 +421,9 @@ export function lstrip(s: string, lStr: string): string {
413421
* C:/code/app.js => file:///C:/code/app.js
414422
* /code/app.js => file:///code/app.js
415423
*/
416-
export function pathToFileURL(path: string): string {
417-
return (path.startsWith('/') ? 'file://' : 'file:///') +
418-
path;
424+
export function pathToFileURL(absPath: string): string {
425+
absPath = forceForwardSlashes(absPath);
426+
absPath = (absPath.startsWith('/') ? 'file://' : 'file:///') +
427+
absPath;
428+
return encodeURI(absPath);
419429
}

webkit/webKitConnection.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,13 @@ class ResReqWebSocket extends EventEmitter {
5353
resolve(ws);
5454
});
5555
ws.on('message', msgStr => {
56-
Logger.log('From target: ' + msgStr);
57-
this.onMessage(JSON.parse(msgStr));
56+
const msgObj = JSON.parse(msgStr);
57+
if (msgObj && !(msgObj.method === "Debugger.scriptParsed" && msgObj.params && msgObj.params.isContentScript) && !(msgObj.params && msgObj.params.url && msgObj.params.url.indexOf('extensions::') === 0)) {
58+
// Not really the right place to examine the content of the message, but don't log annoying extension script notifications.
59+
Logger.log('From target: ' + msgStr);
60+
}
61+
62+
this.onMessage(msgObj);
5863
});
5964
ws.on('close', () => {
6065
Logger.log('Websocket closed');

webkit/webKitDebugAdapter.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,10 @@ export class WebKitDebugAdapter implements IDebugAdapter {
320320
}
321321
}
322322

323+
public setFunctionBreakpoints(): Promise<any> {
324+
return Promise.resolve();
325+
}
326+
323327
private _clearAllBreakpoints(url: string): Promise<void> {
324328
if (!this._committedBreakpointsByUrl.has(url)) {
325329
return Promise.resolve<void>();

0 commit comments

Comments
 (0)