Merge pull request #818 from Microsoft/sourceMapRelativeDirName

Fixes incorrect path resolution of sources to sourcemap when the directory paths differ in only case
This commit is contained in:
Sheetal Nandi
2014-10-06 11:48:10 -07:00
25 changed files with 881 additions and 29 deletions

View File

@@ -476,7 +476,7 @@ module ts {
}
}
export function getRelativePathToDirectoryOrUrl(directoryPathOrUrl: string, relativeOrAbsolutePath: string, currentDirectory: string, isAbsolutePathAnUrl: boolean) {
export function getRelativePathToDirectoryOrUrl(directoryPathOrUrl: string, relativeOrAbsolutePath: string, currentDirectory: string, getCanonicalFileName: (fileName: string) => string, isAbsolutePathAnUrl: boolean) {
var pathComponents = getNormalizedPathOrUrlComponents(relativeOrAbsolutePath, currentDirectory);
var directoryComponents = getNormalizedPathOrUrlComponents(directoryPathOrUrl, currentDirectory);
if (directoryComponents.length > 1 && directoryComponents[directoryComponents.length - 1] === "") {
@@ -487,7 +487,7 @@ module ts {
// Find the component that differs
for (var joinStartIndex = 0; joinStartIndex < pathComponents.length && joinStartIndex < directoryComponents.length; joinStartIndex++) {
if (directoryComponents[joinStartIndex] !== pathComponents[joinStartIndex]) {
if (getCanonicalFileName(directoryComponents[joinStartIndex]) !== getCanonicalFileName(pathComponents[joinStartIndex])) {
break;
}
}

View File

@@ -527,7 +527,8 @@ module ts {
sourceMapData.sourceMapSources.push(getRelativePathToDirectoryOrUrl(sourcesDirectoryPath,
node.filename,
compilerHost.getCurrentDirectory(),
/*isAbsolutePathAnUrl*/ true));
compilerHost.getCanonicalFileName,
/*isAbsolutePathAnUrl*/ true));
sourceMapSourceIndex = sourceMapData.sourceMapSources.length - 1;
// The one that can be used from program to get the actual source file
@@ -669,7 +670,8 @@ module ts {
getDirectoryPath(normalizePath(jsFilePath)), // get the relative sourceMapDir path based on jsFilePath
combinePaths(sourceMapDir, sourceMapData.jsSourceMappingURL), // this is where user expects to see sourceMap
compilerHost.getCurrentDirectory(),
/*isAbsolutePathAnUrl*/ true);
compilerHost.getCanonicalFileName,
/*isAbsolutePathAnUrl*/ true);
}
else {
sourceMapData.jsSourceMappingURL = combinePaths(sourceMapDir, sourceMapData.jsSourceMappingURL);
@@ -3147,7 +3149,8 @@ module ts {
getDirectoryPath(normalizeSlashes(jsFilePath)),
declFileName,
compilerHost.getCurrentDirectory(),
/*isAbsolutePathAnUrl*/ false);
compilerHost.getCanonicalFileName,
/*isAbsolutePathAnUrl*/ false);
referencePathsOutput += "/// <reference path=\"" + declFileName + "\" />" + newLine;
}

View File

@@ -2128,9 +2128,6 @@ module FourSlash {
xmlData.push(xml);
}
// Cache these between executions so we don't have to re-parse them for every test
var fourslashSourceFile: ts.SourceFile = undefined;
export function runFourSlashTestContent(content: string, fileName: string): TestXmlData {
// Parse out the files and their metadata
var testData = parseTestData(content, fileName);
@@ -2138,21 +2135,16 @@ module FourSlash {
currentTestState = new TestState(testData);
var result = '';
var fourslashFilename = 'fourslash.ts';
var tsFn = 'tests/cases/fourslash/' + fourslashFilename;
fourslashSourceFile = fourslashSourceFile || ts.createSourceFile(tsFn, Harness.IO.readFile(tsFn), ts.ScriptTarget.ES5, /*version*/ "0", /*isOpen*/ false);
var files: { [filename: string]: ts.SourceFile; } = {};
files[Harness.Compiler.getCanonicalFileName(fourslashFilename)] = fourslashSourceFile;
files[Harness.Compiler.getCanonicalFileName(fileName)] = ts.createSourceFile(fileName, content, ts.ScriptTarget.ES5, /*version*/ "0", /*isOpen*/ false);
files[Harness.Compiler.getCanonicalFileName(Harness.Compiler.defaultLibFileName)] = Harness.Compiler.defaultLibSourceFile;
var host = Harness.Compiler.createCompilerHost(files, (fn, contents) => result = contents);
var program = ts.createProgram([fourslashFilename, fileName], { out: "fourslashTestOutput.js" }, host);
var host = Harness.Compiler.createCompilerHost([{ unitName: Harness.Compiler.fourslashFilename, content: undefined },
{ unitName: fileName, content: content }],
(fn, contents) => result = contents,
ts.ScriptTarget.ES5,
sys.useCaseSensitiveFileNames);
var program = ts.createProgram([Harness.Compiler.fourslashFilename, fileName], { out: "fourslashTestOutput.js" }, host);
var checker = ts.createTypeChecker(program, /*fullTypeCheckMode*/ true);
checker.checkProgram();
var errs = checker.getDiagnostics(files[fileName]);
var errs = checker.getDiagnostics(program.getSourceFile(fileName));
if (errs.length > 0) {
throw new Error('Error compiling ' + fileName + ': ' + errs.map(e => e.messageText).join('\r\n'));
}

View File

@@ -534,18 +534,47 @@ module Harness {
export var defaultLibFileName = 'lib.d.ts';
export var defaultLibSourceFile = ts.createSourceFile(defaultLibFileName, IO.readFile(libFolder + 'lib.core.d.ts'), /*languageVersion*/ ts.ScriptTarget.ES5, /*version:*/ "0");
// Cache these between executions so we don't have to re-parse them for every test
export var fourslashFilename = 'fourslash.ts';
export var fourslashSourceFile: ts.SourceFile;
export function getCanonicalFileName(fileName: string): string {
return sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
}
export function createCompilerHost(filemap: { [filename: string]: ts.SourceFile; }, writeFile: (fn: string, contents: string, writeByteOrderMark:boolean) => void): ts.CompilerHost {
export function createCompilerHost(inputFiles: { unitName: string; content: string; }[],
writeFile: (fn: string, contents: string, writeByteOrderMark: boolean) => void,
scriptTarget: ts.ScriptTarget,
useCaseSensitiveFileNames: boolean): ts.CompilerHost {
// Local get canonical file name function, that depends on passed in parameter for useCaseSensitiveFileNames
function getCanonicalFileName(fileName: string): string {
return useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
}
var filemap: { [filename: string]: ts.SourceFile; } = {};
// Register input files
function register(file: { unitName: string; content: string; }) {
if (file.content !== undefined) {
var filename = Path.switchToForwardSlashes(file.unitName);
filemap[getCanonicalFileName(filename)] = ts.createSourceFile(filename, file.content, scriptTarget, /*version:*/ "0");
}
};
inputFiles.forEach(register);
return {
getCurrentDirectory: sys.getCurrentDirectory,
getCancellationToken: (): any => undefined,
getSourceFile: (fn, languageVersion) => {
if (Object.prototype.hasOwnProperty.call(filemap, getCanonicalFileName(fn))) {
return filemap[getCanonicalFileName(fn)];
} else {
}
else if (fn === fourslashFilename) {
var tsFn = 'tests/cases/fourslash/' + fourslashFilename;
fourslashSourceFile = fourslashSourceFile || ts.createSourceFile(tsFn, Harness.IO.readFile(tsFn), scriptTarget, /*version*/ "0", /*isOpen*/ false);
return fourslashSourceFile;
}
else {
var lib = defaultLibFileName;
if (fn === defaultLibFileName) {
return defaultLibSourceFile;
@@ -557,7 +586,7 @@ module Harness {
getDefaultLibFilename: () => defaultLibFileName,
writeFile: writeFile,
getCanonicalFileName: getCanonicalFileName,
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
getNewLine: ()=> sys.newLine
};
}
@@ -614,7 +643,7 @@ module Harness {
}
public compileFiles(inputFiles: { unitName: string; content: string }[],
otherFiles: { unitName: string; content?: string }[],
otherFiles: { unitName: string; content: string }[],
onComplete: (result: CompilerResult, checker: ts.TypeChecker) => void,
settingsCallback?: (settings: ts.CompilerOptions) => void,
options?: ts.CompilerOptions) {
@@ -628,9 +657,10 @@ module Harness {
settingsCallback(null);
}
var useCaseSensitiveFileNames = sys.useCaseSensitiveFileNames;
this.settings.forEach(setting => {
switch (setting.flag.toLowerCase()) {
// "filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outDir", "noimplicitany", "noresolve"
// "filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outdir", "noimplicitany", "noresolve"
case "module":
case "modulegentarget":
if (typeof setting.value === 'string') {
@@ -706,10 +736,13 @@ module Harness {
options.removeComments = setting.value === 'false';
break;
case 'usecasesensitivefilenames':
useCaseSensitiveFileNames = setting.value === 'true';
break;
case 'mapsourcefiles':
case 'maproot':
case 'generatedeclarationfiles':
case 'usecasesensitivefileresolution':
case 'gatherDiagnostics':
case 'codepage':
case 'createFileLog':
@@ -748,7 +781,10 @@ module Harness {
var fileOutputs: GeneratedFile[] = [];
var programFiles = inputFiles.map(file => file.unitName);
var program = ts.createProgram(programFiles, options, createCompilerHost(filemap, (fn, contents, writeByteOrderMark) => fileOutputs.push({ fileName: fn, code: contents, writeByteOrderMark: writeByteOrderMark })));
var program = ts.createProgram(programFiles, options, createCompilerHost(inputFiles.concat(otherFiles),
(fn, contents, writeByteOrderMark) => fileOutputs.push({ fileName: fn, code: contents, writeByteOrderMark: writeByteOrderMark }),
options.target,
useCaseSensitiveFileNames));
var hadParseErrors = program.getDiagnostics().length > 0;
@@ -1034,7 +1070,7 @@ module Harness {
var optionRegex = /^[\/]{2}\s*@(\w+)\s*:\s*(\S*)/gm; // multiple matches on multiple lines
// List of allowed metadata names
var fileMetadataNames = ["filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outDir", "noimplicitany", "noresolve", "newline", "newlines", "emitbom", "errortruncation"];
var fileMetadataNames = ["filename", "comments", "declaration", "module", "nolib", "sourcemap", "target", "out", "outdir", "noimplicitany", "noresolve", "newline", "newlines", "emitbom", "errortruncation", "usecasesensitivefilenames"];
function extractCompilerSettings(content: string): CompilerSetting[] {

View File

@@ -226,7 +226,8 @@ class ProjectRunner extends RunnerBase {
? filename
: ts.normalizeSlashes(testCase.projectRoot) + "/" + ts.normalizeSlashes(filename);
var diskRelativeName = ts.getRelativePathToDirectoryOrUrl(testCase.projectRoot, diskFileName, getCurrentDirectory(), false);
var diskRelativeName = ts.getRelativePathToDirectoryOrUrl(testCase.projectRoot, diskFileName,
getCurrentDirectory(), Harness.Compiler.getCanonicalFileName, /*isAbsolutePathAnUrl*/ false);
if (ts.isRootedDiskPath(diskRelativeName) || diskRelativeName.substr(0, 3) === "../") {
// If the generated output file resides in the parent folder or is rooted path,
// we need to instead create files that can live in the project reference folder