Factor out sourcemaps and add tests

This commit is contained in:
Rob 2015-10-20 22:44:33 -07:00
Родитель d9135b7313
Коммит a5b11ed116
16 изменённых файлов: 367 добавлений и 116 удалений

12
.vscode/launch.json поставляемый
Просмотреть файл

@ -13,18 +13,10 @@
},
{
"name": "test",
"type": "webkit",
"program": "./webkit/test/index.html",
"stopOnEntry": false,
"sourceMaps": false,
"outDir": "out"
},
{
"name": "opendebug-node",
"type": "node",
"program": "./out/node/openDebugNode.js",
"program": "./node_modules/gulp/bin/gulp.js",
"stopOnEntry": false,
"args": [ "--server=4712" ],
"args": [ "test" ],
"sourceMaps": false,
"outDir": "out"
}

5
.vscode/tasks.json поставляемый
Просмотреть файл

@ -13,8 +13,9 @@
]
},
{
"taskName": "build-test-watch",
"isWatching": true
"taskName": "watch-build-test",
"isWatching": true,
"isTestCommand": true
}
]
}

Просмотреть файл

@ -35,7 +35,7 @@ export class AdapterProxy {
(p, transformer) => {
// If the transformer implements this command, give it a chance to modify the args. Otherwise skip it
return request.command in transformer ?
p.then(() => transformer[request.command](request.arguments)) :
p.then(() => transformer[request.command](request.arguments, request.seq)) :
p;
}, Promise.resolve<void>());
}
@ -54,7 +54,7 @@ export class AdapterProxy {
// If the transformer implements this command, give it a chance to modify the args. Otherwise skip it
const bodyTransformMethodName = request.command + "Response";
return bodyTransformMethodName in transformer ?
p.then(() => transformer[bodyTransformMethodName](body)) :
p.then(() => transformer[bodyTransformMethodName](body, request.seq)) :
p;
}, Promise.resolve<void>());
}

Просмотреть файл

Просмотреть файл

@ -0,0 +1,80 @@
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
import {ISourceMaps, SourceMaps} from './sourceMaps';
/**
* If sourcemaps are enabled, converts from source files on the client side to runtime files on the target side
*/
export class SourceMapTransformer implements IDebugTransformer {
private _sourceMaps: ISourceMaps;
private _generatedCodeDirectory: string;
private _requestSeqToSetBreakpointsArgs: Map<number, DebugProtocol.SetBreakpointsArguments>;
public initialize(args: IInitializeRequestArgs): void {
if (args.sourceMaps) {
this._sourceMaps = new SourceMaps(args.generatedCodeDirectory);
this._generatedCodeDirectory = args.generatedCodeDirectory;
this._requestSeqToSetBreakpointsArgs = new Map<number, DebugProtocol.SetBreakpointsArguments>();
}
}
public launch(args: ILaunchRequestArgs): void {
// Can html files be sourcemapped? May as well try.
if (this._sourceMaps && args.program) {
const generatedPath = this._sourceMaps.MapPathFromSource(args.program);
if (generatedPath) {
args.program = generatedPath;
}
}
}
public setBreakpoints(args: DebugProtocol.SetBreakpointsArguments, requestSeq: number): void {
if (this._sourceMaps && args.source.path) {
const argsPath = args.source.path;
args.source.path = this._sourceMaps.MapPathFromSource(argsPath) || argsPath;
args.lines = args.lines.map(line => {
const mapped = this._sourceMaps.MapFromSource(argsPath, line, /*column=*/0);
return mapped ? mapped.line : line;
});
this._requestSeqToSetBreakpointsArgs.set(requestSeq, JSON.parse(JSON.stringify(args)));
}
}
public setBreakpointsResponse(response: SetBreakpointsResponseBody, requestSeq: number): void {
if (this._sourceMaps && this._requestSeqToSetBreakpointsArgs.has(requestSeq)) {
const args = this._requestSeqToSetBreakpointsArgs.get(requestSeq);
response.breakpoints.forEach(bp => {
const mapped = this._sourceMaps.MapToSource(args.source.path, bp.line, (<any>bp).column);
delete (<any>bp).column;
if (mapped) {
bp.line = mapped.line;
}
this._requestSeqToSetBreakpointsArgs.delete(requestSeq);
});
} else {
// Cleanup column, which is passed in here in case it's needed for sourcemaps, but isn't actually
// part of the DebugProtocol
response.breakpoints.forEach(bp => {
delete (<any>bp).column;
});
}
}
public stackTraceResponse(response: StackTraceResponseBody): void {
if (this._sourceMaps) {
response.stackFrames.forEach(stackFrame => {
const mapped = this._sourceMaps.MapToSource(stackFrame.source.path, stackFrame.line, stackFrame.column);
if (mapped) {
stackFrame.source.path = mapped.path;
stackFrame.line = mapped.line;
stackFrame.column = mapped.column;
}
});
}
}
}

Просмотреть файл

Просмотреть файл

@ -44,13 +44,16 @@ gulp.task('default', ['build']);
function test() {
return gulp.src('out/test/**/*.test.js', { read: false })
.pipe(mocha())
.on('error', function() { });
.pipe(mocha({ ui: 'tdd' }))
.on('error', function(e) {
log(e ? e.toString() : 'error in test task!');
this.emit('end');
});
}
gulp.task('build-test', ['build'], test);
gulp.task('test', test);
gulp.task('watch-build-test', ['build', 'build-test'], function(cb) {
gulp.task('watch-build-test', ['build', 'build-test'], function() {
return gulp.watch(sources, ['build', 'build-test']);
});

Просмотреть файл

@ -21,6 +21,7 @@
"gulp-typescript": "^2.8.0",
"gulp-util": "^3.0.5",
"mocha": "^2.3.3",
"mockery": "^1.4.0",
"tsd": "^0.6.3",
"typescript": "^1.6.2"
},

Просмотреть файл

@ -14,13 +14,13 @@ function createTransformer(clientLinesStartAt1: boolean, targetLinesStartAt1: bo
return transformer;
}
describe('LineNumberTransformer', () => {
suite('LineNumberTransformer', () => {
const c0t0Transformer = createTransformer(false, false);
const c0t1Transformer = createTransformer(false, true);
const c1t0Transformer = createTransformer(true, false);
const c1t1Transformer = createTransformer(true, true);
describe('setBreakpoints()', () => {
suite('setBreakpoints()', () => {
function getArgs(lines: number[]): DebugProtocol.SetBreakpointsArguments {
return {
source: { path: "test/path" },
@ -34,7 +34,7 @@ describe('LineNumberTransformer', () => {
assert.deepEqual(args, getArgs(tLines));
}
it('fixes args.lines', () => {
test('fixes args.lines', () => {
testSetBreakpoints(c0t0Transformer, [0, 1, 2]);
testSetBreakpoints(c0t1Transformer, [0, 1, 2], [1, 2, 3]);
testSetBreakpoints(c1t0Transformer, [1, 2, 3], [0, 1, 2]);
@ -42,7 +42,7 @@ describe('LineNumberTransformer', () => {
});
});
describe('setBreakpointsResponse()', () => {
suite('setBreakpointsResponse()', () => {
function getResponse(lines: number[]): SetBreakpointsResponseBody {
return {
breakpoints: lines.map(line => ({ verified: true, line: line }))
@ -55,7 +55,7 @@ describe('LineNumberTransformer', () => {
assert.deepEqual(response, getResponse(cLines));
}
it('fixes the breakpoints\' lines', () => {
test('fixes the breakpoints\' lines', () => {
testSetBreakpointsResponse(c0t0Transformer, [0, 1, 2]);
testSetBreakpointsResponse(c0t1Transformer, [1, 2, 3], [0, 1, 2]);
testSetBreakpointsResponse(c1t0Transformer, [0, 1, 2], [1, 2, 3]);
@ -63,7 +63,7 @@ describe('LineNumberTransformer', () => {
});
});
describe('stackTraceResponse', () => {
suite('stackTraceResponse()', () => {
function getResponse(lines: number[]): StackTraceResponseBody {
return {
stackFrames: lines.map(line => ({ id: 0, name: '', line, column: 0 }))
@ -76,11 +76,11 @@ describe('LineNumberTransformer', () => {
assert.deepEqual(response, getResponse(cLines));
}
it('fixes the stackFrames\' lines', () => {
test('fixes the stackFrames\' lines', () => {
testStackTraceResponse(c0t0Transformer, [0, 1, 2]);
testStackTraceResponse(c0t1Transformer, [1, 2, 3], [0, 1, 2]);
testStackTraceResponse(c1t0Transformer, [0, 1, 2], [1, 2, 3]);
testStackTraceResponse(c1t1Transformer, [1, 2, 3]);
})
});
});
});

Просмотреть файл

@ -0,0 +1,199 @@
/*---------------------------------------------------------
* Copyright (C) Microsoft Corporation. All rights reserved.
*--------------------------------------------------------*/
import assert = require('assert');
import mockery = require('mockery');
import { ISourceMaps, MappingResult } from '../../../adapter/sourceMaps/sourceMaps';
const MODULE_UNDER_TEST = '../../../adapter/sourceMaps/sourceMapTransformer';
const AUTHORED_PATH = 'authored.ts';
const RUNTIME_PATH = 'runtime.js';
const AUTHORED_LINES = [1, 2, 3];
const RUNTIME_LINES = [2, 5, 8];
suite('SourceMapTransformer', () => {
let transformer: IDebugTransformer;
let transformerSMDisabled: IDebugTransformer;
setup(() => {
// Set up mockery with SourceMaps mock
mockery.enable();
mockery.registerMock('./sourceMaps', { SourceMaps: MockSourceMaps });
mockery.registerAllowable(MODULE_UNDER_TEST);
// Grab the test class with mock injected, instantiate with and without sourcemaps enabled
let SourceMapTransformer = require(MODULE_UNDER_TEST).SourceMapTransformer;
transformer = new SourceMapTransformer();
transformer.initialize(<IInitializeRequestArgs><any>{
sourceMaps: true,
generatedCodeDirectory: 'test'
});
transformerSMDisabled = new SourceMapTransformer();
transformerSMDisabled.initialize(<IInitializeRequestArgs><any>{
sourceMaps: false,
generatedCodeDirectory: 'test'
});
});
teardown(() => {
mockery.deregisterAll();
mockery.disable();
transformer = null;
transformerSMDisabled = null;
});
suite('launch()', () => {
test('modifies args.path when present', () => {
const args = <ILaunchRequestArgs>{ workingDirectory: 'C:/code', program: 'authored.ts' };
const expected = <ILaunchRequestArgs>{ workingDirectory: 'C:/code', program: 'runtime.js' };
transformer.launch(args);
assert.deepEqual(args, expected);
});
test('doesn\'t do anything when args.path is missing, e.g. args.url was set', () => {
const args = <ILaunchRequestArgs>{ workingDirectory: 'C:/code' };
const expected = <ILaunchRequestArgs>{ workingDirectory: 'C:/code' };
transformer.launch(args);
assert.deepEqual(args, expected);
});
test('doesn\'t do anything when sourcemaps are disabled', () => {
const args = <ILaunchRequestArgs>{ workingDirectory: 'C:/code' };
const expected = <ILaunchRequestArgs>{ workingDirectory: 'C:/code' };
transformerSMDisabled.launch(args);
assert.deepEqual(args, expected);
});
});
suite('setBreakpoints()', () => {
function createArgs(path: string, lines:number[]): DebugProtocol.SetBreakpointsArguments {
return {
source: { path },
lines
};
}
test('modifies the source and lines', () => {
const args = createArgs(AUTHORED_PATH, AUTHORED_LINES);
const expected = createArgs(RUNTIME_PATH, RUNTIME_LINES);
transformer.setBreakpoints(args);
assert.deepEqual(args, expected);
});
test('doesn\'t do anything when sourcemaps are disabled', () => {
const args = createArgs(RUNTIME_PATH, RUNTIME_LINES);
const expected = createArgs(RUNTIME_PATH, RUNTIME_LINES);
transformerSMDisabled.setBreakpoints(args);
assert.deepEqual(args, expected);
});
suite('setBreakpointsResponse()', () => {
function getResponseBody(lines: number[], column?: number): SetBreakpointsResponseBody {
return {
breakpoints: lines.map(line => {
const bp = { line, verified: true };
if (column !== undefined) {
(<any>bp).column = column;
}
return bp;
})
};
}
test('modifies the response source and lines', () => {
const response = getResponseBody(RUNTIME_LINES, /*column=*/0);
const expected = getResponseBody(AUTHORED_LINES);
transformer.setBreakpoints(<DebugProtocol.SetBreakpointsArguments>{
source: { path: AUTHORED_PATH },
lines: AUTHORED_LINES
});
transformer.setBreakpointsResponse(response);
assert.deepEqual(response, expected);
});
test('doesn\'t do anything when sourcemaps are disabled except remove the column', () => {
const response = getResponseBody(RUNTIME_LINES, /*column=*/0);
const expected = getResponseBody(RUNTIME_LINES);
transformerSMDisabled.setBreakpoints(<DebugProtocol.SetBreakpointsArguments>{
source: { path: RUNTIME_PATH },
lines: RUNTIME_LINES
});
transformerSMDisabled.setBreakpointsResponse(response);
assert.deepEqual(response, expected);
});
});
});
suite('stackTraceResponse', () => {
function getResponseBody(path: string, lines: number[]): StackTraceResponseBody {
return {
stackFrames: lines.map((line, i) => ({
id: i,
name: 'line ' + i,
line,
column: 0,
source: { path }
}))
};
}
test('modifies the response stackFrames', () => {
const response = getResponseBody(RUNTIME_PATH, RUNTIME_LINES);
const expected = getResponseBody(AUTHORED_PATH, AUTHORED_LINES);
transformer.stackTraceResponse(response);
assert.deepEqual(response, expected);
});
test('does nothing when there are no sourcemaps', () => {
const response = getResponseBody(RUNTIME_PATH, RUNTIME_LINES);
const expected = getResponseBody(RUNTIME_PATH, RUNTIME_LINES);
transformerSMDisabled.stackTraceResponse(response);
assert.deepEqual(response, expected);
});
});
});
class MockSourceMaps implements ISourceMaps {
constructor(private generatedCodeDirectory: string) { }
public MapPathFromSource(path: string): string {
assert.equal(path, AUTHORED_PATH);
return RUNTIME_PATH;
}
/*
* Map location in source language to location in generated code.
* line and column are 0 based.
*/
public MapFromSource(path: string, line: number, column: number): MappingResult {
assert.equal(path, AUTHORED_PATH);
assert.equal(column, 0);
const mappedLine = RUNTIME_LINES[AUTHORED_LINES.indexOf(line)];
return { path: RUNTIME_PATH, line: mappedLine, column: 0 };
}
/*
* Map location in generated code to location in source language.
* line and column are 0 based.
*/
public MapToSource(path: string, line: number, column: number): MappingResult {
assert.equal(path, RUNTIME_PATH);
assert.equal(column, 0);
const mappedLine = AUTHORED_LINES[RUNTIME_LINES.indexOf(line)];
return { path: AUTHORED_PATH, line: mappedLine, column: 0 };
}
}

2
testapp/.vscode/launch.json поставляемый
Просмотреть файл

@ -9,7 +9,7 @@
"runtimeArgs": ["http://localhost:8080/out/client/index.html?2"],
"cwd": ".",
"stopOnEntry": false,
"sourceMaps": false,
"sourceMaps": true,
"outDir": "out"
},
{

Просмотреть файл

@ -6,27 +6,5 @@
"target": "ES5",
"sourceMap": true,
"outDir": "out"
},
"files": [
"adapter/adapterProxy.ts",
"adapter/lineNumberTransformer.ts",
"webkit/openDebugWebKit.ts",
"webkit/pathUtilities.ts",
"webkit/sourceMaps.ts",
"webkit/utilities.ts",
"webkit/webKitConnection.ts",
"webkit/webKitDebugAdapter.ts",
"webkit/webKitDebugSession.ts",
"webkit/webKitProtocol.d.ts",
"webkit/webKitAdapterInterfaces.d.ts",
"common/debugProtocol.d.ts",
"common/debugSession.ts",
"common/handles.ts",
"common/v8Protocol.ts",
"typings/es6-collections/es6-collections.d.ts",
"typings/es6-promise/es6-promise.d.ts",
"typings/node/node.d.ts",
"typings/source-map/source-map.d.ts",
"typings/ws/ws.d.ts"
]
}
}

33
typings/mockery/mockery.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,33 @@
// Type definitions for mockery 1.4.0
// Project: https://github.com/mfncooper/mockery
// Definitions by: jt000 <https://github.com/jt000>
// Definitions: https://github.com/borisyankov/DefinitelyTyped
declare module "mockery" {
interface MockeryEnableArgs {
useCleanCache?: boolean;
warnOnReplace?: boolean;
warnOnUnregistered?: boolean;
}
export function enable(args?: MockeryEnableArgs): void;
export function disable(): void;
export function registerMock(name: string, mock: any): void;
export function deregisterMock(name: string): void;
export function registerSubstitute(name: string, substitute: string): void;
export function deregisterSubstitute(name: string): void;
export function registerAllowable(name: string, unhook?: boolean): void;
export function deregisterAllowable(name: string): void;
export function registerAllowables(names: string[]): void;
export function deregisterAllowables(names: string[]): void;
export function deregisterAll(): void;
export function resetCache(): void;
export function warnOnUnregistered(value: boolean): void;
export function warnOnReplace(value: boolean): void;
}

34
webkit/webKitAdapterInterfaces.d.ts поставляемый
Просмотреть файл

@ -77,23 +77,23 @@ interface IDebugAdapter {
declare type PromiseOrNot<T> = T | Promise<T>;
interface IDebugTransformer {
initialize?(args: IInitializeRequestArgs): PromiseOrNot<void>;
launch?(args: ILaunchRequestArgs): PromiseOrNot<void>;
attach?(args: IAttachRequestArgs): PromiseOrNot<void>;
setBreakpoints?(args: DebugProtocol.SetBreakpointsArguments): PromiseOrNot<void>;
setExceptionBreakpoints?(args: DebugProtocol.SetExceptionBreakpointsArguments): PromiseOrNot<void>;
initialize?(args: IInitializeRequestArgs, requestSeq?: number): PromiseOrNot<void>;
launch?(args: ILaunchRequestArgs, requestSeq?: number): PromiseOrNot<void>;
attach?(args: IAttachRequestArgs, requestSeq?: number): PromiseOrNot<void>;
setBreakpoints?(args: DebugProtocol.SetBreakpointsArguments, requestSeq?: number): PromiseOrNot<void>;
setExceptionBreakpoints?(args: DebugProtocol.SetExceptionBreakpointsArguments, requestSeq?: number): PromiseOrNot<void>;
stackTrace?(args: DebugProtocol.StackTraceArguments): PromiseOrNot<void>;
scopes?(args: DebugProtocol.ScopesArguments): PromiseOrNot<void>;
variables?(args: DebugProtocol.VariablesArguments): PromiseOrNot<void>;
source?(args: DebugProtocol.SourceArguments): PromiseOrNot<void>;
evaluate?(args: DebugProtocol.EvaluateArguments): PromiseOrNot<void>;
stackTrace?(args: DebugProtocol.StackTraceArguments, requestSeq?: number): PromiseOrNot<void>;
scopes?(args: DebugProtocol.ScopesArguments, requestSeq?: number): PromiseOrNot<void>;
variables?(args: DebugProtocol.VariablesArguments, requestSeq?: number): PromiseOrNot<void>;
source?(args: DebugProtocol.SourceArguments, requestSeq?: number): PromiseOrNot<void>;
evaluate?(args: DebugProtocol.EvaluateArguments, requestSeq?: number): PromiseOrNot<void>;
setBreakpointsResponse?(response: SetBreakpointsResponseBody): PromiseOrNot<void>;
stackTraceResponse?(response: StackTraceResponseBody): PromiseOrNot<void>;
scopesResponse?(response: ScopesResponseBody): PromiseOrNot<void>;
variablesResponse?(response: VariablesResponseBody): PromiseOrNot<void>;
sourceResponse?(response: SourceResponseBody): PromiseOrNot<void>;
threadsResponse?(response: ThreadsResponseBody): PromiseOrNot<void>;
evaluateResponse?(response: EvaluateResponseBody): PromiseOrNot<void>;
setBreakpointsResponse?(response: SetBreakpointsResponseBody, requestSeq?: number): PromiseOrNot<void>;
stackTraceResponse?(response: StackTraceResponseBody, requestSeq?: number): PromiseOrNot<void>;
scopesResponse?(response: ScopesResponseBody, requestSeq?: number): PromiseOrNot<void>;
variablesResponse?(response: VariablesResponseBody, requestSeq?: number): PromiseOrNot<void>;
sourceResponse?(response: SourceResponseBody, requestSeq?: number): PromiseOrNot<void>;
threadsResponse?(response: ThreadsResponseBody, requestSeq?: number): PromiseOrNot<void>;
evaluateResponse?(response: EvaluateResponseBody, requestSeq?: number): PromiseOrNot<void>;
}

Просмотреть файл

@ -6,7 +6,6 @@ import {DebugSession, StoppedEvent, InitializedEvent, TerminatedEvent} from '../
import {Handles} from '../common/handles';
import {WebKitConnection} from './webKitConnection';
import Utilities = require('./utilities');
import {ISourceMaps, SourceMaps} from './sourceMaps';
import {spawn, ChildProcess} from 'child_process';
import nodeUrl = require('url');
@ -32,8 +31,6 @@ export class WebKitDebugAdapter implements IDebugAdapter {
private _currentStack: WebKitProtocol.Debugger.CallFrame[];
private _pendingBreakpointsByUrl: Map<string, IPendingBreakpoint>;
private _committedBreakpointsByScriptId: Map<WebKitProtocol.Debugger.ScriptId, WebKitProtocol.Debugger.BreakpointId[]>;
private _sourceMaps: ISourceMaps;
private _generatedCodeDirectory: string;
private _overlayHelper: Utilities.DebounceHelper;
private _chromeProc: ChildProcess;
@ -75,11 +72,6 @@ export class WebKitDebugAdapter implements IDebugAdapter {
public initialize(args: IInitializeRequestArgs): Promise<void> {
this._clientLinesStartAt1 = args.linesStartAt1;
if (args.sourceMaps) {
this._sourceMaps = new SourceMaps(args.generatedCodeDirectory);
this._generatedCodeDirectory = args.generatedCodeDirectory;
}
return Promise.resolve<void>();
}
@ -98,17 +90,11 @@ export class WebKitDebugAdapter implements IDebugAdapter {
}
if (args.program) {
// Can html files be sourcemapped? May as well try.
if (this._sourceMaps) {
const generatedPath = this._sourceMaps.MapPathFromSource(args.program);
if (generatedPath) {
args.program = generatedPath;
}
}
chromeArgs.push(args.program);
} else if (args.url) {
chromeArgs.push(args.url);
} else {
// TODO fail
}
if (args.arguments) {
@ -234,9 +220,7 @@ export class WebKitDebugAdapter implements IDebugAdapter {
private _setAllBreakpoints(args: DebugProtocol.SetBreakpointsArguments): Promise<SetBreakpointsResponseBody> {
let targetScript: WebKitProtocol.Debugger.Script;
if (args.source.path) {
const path = (this._sourceMaps && this._sourceMaps.MapPathFromSource(args.source.path)) || args.source.path;
const canPath = canonicalizeUrl(path);
targetScript = this._scriptsByUrl.get(canPath);
targetScript = this._scriptsByUrl.get(canonicalizeUrl(args.source.path));
} else if (args.source.sourceReference) {
targetScript = this._scriptsById.get(sourceReferenceToScriptId(args.source.sourceReference));
} else if (args.source.name) {
@ -263,15 +247,6 @@ export class WebKitDebugAdapter implements IDebugAdapter {
private _addBreakpoints(sourcePath: string, scriptId: WebKitProtocol.Debugger.ScriptId, lines: number[]): Promise<WebKitProtocol.Debugger.SetBreakpointResponse[]> {
// Adjust lines for sourcemaps, call setBreakpoint for all breakpoints in the script simultaneously
const responsePs = lines
.map(debuggerLine => {
// Sourcemap lines
if (this._sourceMaps) {
const mapped = this._sourceMaps.MapFromSource(sourcePath, debuggerLine, /*column=*/0);
return mapped ? mapped.line : debuggerLine;
} else {
return debuggerLine;
}
})
.map(lineNumber => this._webKitConnection.debugger_setBreakpoint({ scriptId: scriptId, lineNumber }));
// Join all setBreakpoint requests to a single promise
@ -290,18 +265,11 @@ export class WebKitDebugAdapter implements IDebugAdapter {
return successfulResponses
.map(response => {
let line = response.result.actualLocation.lineNumber;
if (this._sourceMaps) {
const clientUrl = this.webkitUrlToClientUrl(script.url);
const mapped = this._sourceMaps.MapToSource(clientUrl, response.result.actualLocation.lineNumber, response.result.actualLocation.columnNumber);
if (mapped) {
line = mapped.line;
}
}
return <DebugProtocol.Breakpoint>{
verified: true,
line: line
}
line,
column: response.result.actualLocation.columnNumber
};
});
}
@ -350,15 +318,8 @@ export class WebKitDebugAdapter implements IDebugAdapter {
let path = this.webkitUrlToClientUrl(script.url);
let line = callFrame.location.lineNumber;
let column = callFrame.location.columnNumber;
if (this._sourceMaps) {
const mapped = this._sourceMaps.MapToSource(path, line, column);
if (mapped) {
path = mapped.path;
line = mapped.line;
column = mapped.column;
}
}
// Both?
const source = <DebugProtocol.Source>{
path,
sourceReference: scriptIdToSourceReference(script.scriptId)
@ -398,7 +359,7 @@ export class WebKitDebugAdapter implements IDebugAdapter {
return { variables };
});
} else {
return Promise.resolve<VariablesResponseBody>();
return Promise.resolve(null);
}
}
@ -506,8 +467,7 @@ export class WebKitDebugAdapter implements IDebugAdapter {
const pathParts = pathName.split('/');
while (pathParts.length > 0) {
const rootDir = this._sourceMaps ? this._generatedCodeDirectory : this._clientCWD;
const clientUrl = path.join(rootDir, pathParts.join('/'));
const clientUrl = path.join(this._clientCWD, pathParts.join('/'));
if (fs.existsSync(clientUrl)) {
return canonicalizeUrl(clientUrl); // path.join will change / to \
}

Просмотреть файл

@ -8,6 +8,7 @@ import {WebKitDebugAdapter} from './webKitDebugAdapter';
import {AdapterProxy} from '../adapter/adapterProxy';
import {LineNumberTransformer} from '../adapter/lineNumberTransformer';
import {SourceMapTransformer} from '../adapter/sourceMaps/sourceMapTransformer';
export class WebKitDebugSession extends DebugSession {
private _adapterProxy: AdapterProxy;
@ -16,7 +17,10 @@ export class WebKitDebugSession extends DebugSession {
super(targetLinesStartAt1, isServer);
this._adapterProxy = new AdapterProxy(
[new LineNumberTransformer(targetLinesStartAt1)],
[
new LineNumberTransformer(targetLinesStartAt1),
new SourceMapTransformer()
],
new WebKitDebugAdapter(),
event => this.sendEvent(event));
}