Skip to content

Patch for multi disk support on Windows(TS Sourcemap) #493

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ node_modules/
out/
.vscode-test/
coverage/
.idea

# Sample Application auto-generated files
SampleApplication/.vscode/.react/debuggerWorker.js
Expand Down
31 changes: 25 additions & 6 deletions src/debugger/sourceMapsCombinator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import * as path from "path";
import { SourceMapConsumer, RawSourceMap, SourceMapGenerator, MappingItem, Mapping, Position, MappedPosition } from "source-map";
import sourceMapResolve = require("source-map-resolve");

const DISK_LETTER_RE: RegExp = /^[a-z]:/i;

export class SourceMapsCombinator {

public convert(rawBundleSourcemap: RawSourceMap): RawSourceMap {
Expand Down Expand Up @@ -59,11 +61,13 @@ export class SourceMapsCombinator {

// Resolve TS source path to absolute because it might be relative to generated JS
// (this depends on whether "sourceRoot" option is specified in tsconfig.json)
tsPosition.source = path.resolve(
rawBundleSourcemap.sourceRoot,
path.dirname(item.source),
tsPosition.source
);
if (!tsPosition.source.match(DISK_LETTER_RE)) { // This check for Windows tests which were run on MacOs
tsPosition.source = path.resolve(
rawBundleSourcemap.sourceRoot,
path.dirname(item.source),
tsPosition.source
);
}

// Update mapping w/ mapped position values
mapping = {
Expand All @@ -90,10 +94,25 @@ export class SourceMapsCombinator {
}

private readSourcemap(file: string, code: string): SourceMapConsumer | null {
let result = sourceMapResolve.resolveSync(code, file, fs.readFileSync);
let result = sourceMapResolve.resolveSync(code, file, readFileSync.bind(null, getDiskLetter(file)));
if (result === null) {
return null;
}
return new SourceMapConsumer(result.map);
}
}

// Hack for source-map-resolve and cutted disk letter
// https://github.com/lydell/source-map-resolve/issues/9
function readFileSync(diskLetter: string, filePath: string) {
if (filePath.match(DISK_LETTER_RE)) {
return fs.readFileSync(filePath);
} else {
return fs.readFileSync(`${diskLetter}${filePath}`);
}
}

function getDiskLetter(filePath: string): string {
const matched = filePath.match(DISK_LETTER_RE);
return matched ? matched[0] : "";
}
13 changes: 13 additions & 0 deletions src/test/debugger/assets/hello.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
class Hello {
constructor (public msg: string) {
}
public sayHello() {
return this.msg;
}
}

const hello = new Hello("HelloWorld!");

console.log(hello.sayHello());
70 changes: 70 additions & 0 deletions src/test/debugger/sourceMapsCombinator.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.

import { SourceMapsCombinator } from "../../debugger/sourceMapsCombinator";

import * as assert from "assert";
import * as sinon from "sinon";
import * as fs from "fs";
import * as path from "path";

suite("sourceMapsCombinator", function () {
let sandbox: Sinon.SinonSandbox;

setup(() => {
sandbox = sinon.sandbox.create();
});

suiteTeardown(() => {
sandbox.restore();
});

suite("#convert", function () {
test("convert sourcemap", function () {
const pathToJS = "d:/hello.js";
const pathToTS = "d:/hello.ts";
const sourcemapPath = "d:/hello.js.map";
const codeJS = fs.readFileSync(path.resolve(__dirname, "assets/hello.js"));
const codeTS = fs.readFileSync(path.resolve(__dirname, "../../../src/test/debugger/assets/hello.ts"));
const sourcemap = {
"version": 3,
"sources": [
"d:/hello.ts",
],
"names": [],
"mappings": "AAAA,MAAM,MAAM;IACR,YAAY,CAAC,OAAO,GAAG,EAAE,MAAM,CAAC;IAChC;IACA,OAAO,QAAQ,CAAC,EAAE;QACd,OAAO,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO;IACtC;AACJ;;AAEA,MAAM,MAAM,EAAE,IAAI,KAAK,CAAC,gDAAgD,CAAC;;AAEzE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC", "file": "hello.js", "sourceRoot": "",
};

const expected = {
"version": 3,
"sources": [
"d:/hello.ts",
],
"names": [],
"mappings": "AAAA,IAAA,MAAM,EAAM,CAAA,SAAA,CAAA,EAAA;IACR,SAAA,KAAa,CAAA,GAAA,EAAO;QACpB,IAAA,CAAA,IAAA,EAAA,GAAA;IACA;SACI,CAAA,SAAO,CAAA,SAAc,EAAA,SAAM,CAAA,EAAO;QACtC,OAAA,OAAA,EAAA,IAAA,CAAA,IAAA,EAAA,OAAA;IACJ,CAAA;;AAEA,CAAA,CAAA,CAAA,CAAA;;AAEA,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC",
};

let rawBundleSourcemap = {
"version": 3,
"sources": [
"d:/hello.js",
],
"names": [],
"mappings": "AAAA,IAAI,MAAM,EAAE,CAAC,SAAS,CAAC,EAAE;IACrB,SAAS,KAAK,CAAC,GAAG,EAAE;QAChB,IAAI,CAAC,IAAI,EAAE,GAAG;IAClB;IACA,KAAK,CAAC,SAAS,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE;QACnC,OAAO,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO;IACtC,CAAC;IACD,OAAO,KAAK;AAChB,CAAC,CAAC,CAAC,CAAC;AACJ,IAAI,MAAM,EAAE,IAAI,KAAK,CAAC,gDAAgD,CAAC;AACvE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC", "file": "hello.js", "sourceRoot": "",
};

const fsReadFileStub = sandbox.stub(fs, "readFileSync");

fsReadFileStub.withArgs(pathToJS).returns(codeJS);
fsReadFileStub.withArgs(pathToTS).returns(codeTS);
fsReadFileStub.withArgs(sourcemapPath).returns(JSON.stringify(sourcemap));

let sourceMapsCombinator = new SourceMapsCombinator();
let result = sourceMapsCombinator.convert(rawBundleSourcemap);
result.sources = result.sources.map(p => {
return p.replace(/\\/g, "/");
});
assert.deepEqual(expected, result);
});
});
});