Skip to content

Commit dae5a62

Browse files
committed
record resolution for relative file name if file was found via absolute name
1 parent d9559d5 commit dae5a62

File tree

2 files changed

+109
-45
lines changed

2 files changed

+109
-45
lines changed

src/compiler/program.ts

Lines changed: 47 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -775,60 +775,62 @@ namespace ts {
775775

776776
// Get source file from normalized fileName
777777
function findSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
778-
let canonicalName = host.getCanonicalFileName(normalizeSlashes(fileName));
779-
if (filesByName.contains(canonicalName)) {
778+
if (filesByName.contains(fileName)) {
780779
// We've already looked for this file, use cached result
781-
return getSourceFileFromCache(fileName, canonicalName, /*useAbsolutePath*/ false);
780+
return getSourceFileFromCache(fileName, /*useAbsolutePath*/ false);
781+
}
782+
783+
let normalizedAbsolutePath = getNormalizedAbsolutePath(fileName, host.getCurrentDirectory());
784+
if (filesByName.contains(normalizedAbsolutePath)) {
785+
const file = getSourceFileFromCache(normalizedAbsolutePath, /*useAbsolutePath*/ true);
786+
// we don't have resolution for this relative file name but the match was found by absolute file name
787+
// store resolution for relative name as well
788+
filesByName.set(fileName, file);
789+
return file;
782790
}
783-
else {
784-
let normalizedAbsolutePath = getNormalizedAbsolutePath(fileName, host.getCurrentDirectory());
785-
let canonicalAbsolutePath = host.getCanonicalFileName(normalizedAbsolutePath);
786-
if (filesByName.contains(canonicalAbsolutePath)) {
787-
return getSourceFileFromCache(normalizedAbsolutePath, canonicalAbsolutePath, /*useAbsolutePath*/ true);
788-
}
789791

790-
// We haven't looked for this file, do so now and cache result
791-
let file = host.getSourceFile(fileName, options.target, hostErrorMessage => {
792-
if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) {
793-
fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos,
794-
Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage));
795-
}
796-
else {
797-
fileProcessingDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage));
798-
}
799-
});
800-
filesByName.set(canonicalName, file);
801-
if (file) {
802-
skipDefaultLib = skipDefaultLib || file.hasNoDefaultLib;
792+
// We haven't looked for this file, do so now and cache result
793+
let file = host.getSourceFile(fileName, options.target, hostErrorMessage => {
794+
if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) {
795+
fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos,
796+
Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage));
797+
}
798+
else {
799+
fileProcessingDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage));
800+
}
801+
});
802+
803+
filesByName.set(fileName, file);
804+
if (file) {
805+
skipDefaultLib = skipDefaultLib || file.hasNoDefaultLib;
803806

804-
// Set the source file for normalized absolute path
805-
filesByName.set(canonicalAbsolutePath, file);
806-
807-
let basePath = getDirectoryPath(fileName);
808-
if (!options.noResolve) {
809-
processReferencedFiles(file, basePath);
810-
}
807+
// Set the source file for normalized absolute path
808+
filesByName.set(normalizedAbsolutePath, file);
809+
810+
let basePath = getDirectoryPath(fileName);
811+
if (!options.noResolve) {
812+
processReferencedFiles(file, basePath);
813+
}
811814

812-
// always process imported modules to record module name resolutions
813-
processImportedModules(file, basePath);
815+
// always process imported modules to record module name resolutions
816+
processImportedModules(file, basePath);
814817

815-
if (isDefaultLib) {
816-
file.isDefaultLib = true;
817-
files.unshift(file);
818-
}
819-
else {
820-
files.push(file);
821-
}
818+
if (isDefaultLib) {
819+
file.isDefaultLib = true;
820+
files.unshift(file);
821+
}
822+
else {
823+
files.push(file);
822824
}
823-
824-
return file;
825825
}
826826

827-
function getSourceFileFromCache(fileName: string, canonicalName: string, useAbsolutePath: boolean): SourceFile {
828-
let file = filesByName.get(canonicalName);
827+
return file;
828+
829+
function getSourceFileFromCache(fileName: string, useAbsolutePath: boolean): SourceFile {
830+
let file = filesByName.get(fileName);
829831
if (file && host.useCaseSensitiveFileNames()) {
830832
let sourceFileName = useAbsolutePath ? getNormalizedAbsolutePath(file.fileName, host.getCurrentDirectory()) : file.fileName;
831-
if (canonicalName !== sourceFileName) {
833+
if (normalizeSlashes(fileName) !== normalizeSlashes(sourceFileName)) {
832834
if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) {
833835
fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos,
834836
Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, fileName, sourceFileName));
@@ -862,8 +864,8 @@ namespace ts {
862864
const importedFile = findModuleSourceFile(resolution.resolvedFileName, file.imports[i]);
863865
if (importedFile && resolution.isExternalLibraryImport) {
864866
if (!isExternalModule(importedFile)) {
865-
let start = getTokenPosOfNode(file.imports[i], file)
866-
fileProcessingDiagnostics.add(createFileDiagnostic(file, start, file.imports[i].end - start, Diagnostics.Exported_external_package_typings_file_0_is_not_a_module_Please_contact_the_package_author_to_update_the_package_definition, importedFile.fileName));
867+
let start = getTokenPosOfNode(file.imports[i], file)
868+
fileProcessingDiagnostics.add(createFileDiagnostic(file, start, file.imports[i].end - start, Diagnostics.Exported_external_package_typings_file_0_is_not_a_module_Please_contact_the_package_author_to_update_the_package_definition, importedFile.fileName));
867869
}
868870
else if (!fileExtensionIs(importedFile.fileName, ".d.ts")) {
869871
let start = getTokenPosOfNode(file.imports[i], file)

tests/cases/unittests/moduleResolution.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,4 +163,66 @@ module ts {
163163
]);
164164
});
165165
});
166+
167+
describe("Module resolution - relative imports", () => {
168+
it("should find all modules", () => {
169+
const options: CompilerOptions = { module: ModuleKind.CommonJS };
170+
const files: Map<string> = {
171+
"/a/b/c/first/shared.ts": `
172+
class A {}
173+
export = A`,
174+
"/a/b/c/first/second/class_a.ts": `
175+
import Shared = require('../shared');
176+
import C = require('../../third/class_c');
177+
class B {}
178+
export = B;`,
179+
"/a/b/c/third/class_c.ts":`
180+
import Shared = require('../first/shared');
181+
class C {}
182+
export = C;
183+
`
184+
};
185+
const currentDirectory = "/a/b/c/first/second";
186+
const host: CompilerHost = {
187+
getSourceFile: (fileName: string, languageVersion: ScriptTarget) => {
188+
let path = normalizePath(combinePaths(currentDirectory, fileName));
189+
return hasProperty(files, path) ? createSourceFile(fileName, files[path], languageVersion) : undefined;
190+
},
191+
getDefaultLibFileName: () => "lib.d.ts",
192+
writeFile: (fileName, content): void => { throw new Error("NotImplemented"); },
193+
getCurrentDirectory: () => currentDirectory,
194+
getCanonicalFileName: fileName => fileName.toLowerCase(),
195+
getNewLine: () => "\r\n",
196+
useCaseSensitiveFileNames: () => false,
197+
fileExists: fileName => {
198+
let path = normalizePath(combinePaths(currentDirectory, fileName));
199+
return hasProperty(files, path);
200+
},
201+
readFile: (fileName): string => { throw new Error("NotImplemented"); }
202+
};
203+
204+
const program = createProgram(["class_a.ts"], options, host);
205+
206+
assert.equal(program.getSourceFiles().length, 3);
207+
const syntacticDiagnostics = program.getSyntacticDiagnostics();
208+
assert.equal(syntacticDiagnostics.length, 0, `expect no syntactic diagnostics, got: ${JSON.stringify(syntacticDiagnostics.map(diagnosticToString))}`);
209+
const semanticDiagnostics = program.getSemanticDiagnostics();
210+
assert.equal(semanticDiagnostics.length, 0, `expect no semantic diagnostics, got: ${JSON.stringify(semanticDiagnostics.map(diagnosticToString))}`);
211+
});
212+
213+
function diagnosticToString(diagnostic: Diagnostic) {
214+
let output = "";
215+
216+
if (diagnostic.file) {
217+
let loc = getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start);
218+
219+
output += `${ diagnostic.file.fileName }(${ loc.line + 1 },${ loc.character + 1 }): `;
220+
}
221+
222+
let category = DiagnosticCategory[diagnostic.category].toLowerCase();
223+
output += `${ category } TS${ diagnostic.code }: ${ flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine) }${ sys.newLine }`;
224+
225+
return output;
226+
}
227+
});
166228
}

0 commit comments

Comments
 (0)