Skip to content

Commit d4ce70d

Browse files
committed
external modules resolve by node_modules and package.json-main
1 parent 57b6f0a commit d4ce70d

File tree

4 files changed

+66
-23
lines changed

4 files changed

+66
-23
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
node_modules/
2+
!tests/**/node_modules/
23
built/*
34
tests/cases/*.js
45
tests/cases/*/*.js

src/compiler/checker.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -859,17 +859,9 @@ module ts {
859859
}
860860
let fileName: string;
861861
let sourceFile: SourceFile;
862-
while (true) {
863-
fileName = normalizePath(combinePaths(searchPath, moduleName));
864-
sourceFile = forEach(supportedExtensions, extension => host.getSourceFile(fileName + extension));
865-
if (sourceFile || isRelative) {
866-
break;
867-
}
868-
let parentPath = getDirectoryPath(searchPath);
869-
if (parentPath === searchPath) {
870-
break;
871-
}
872-
searchPath = parentPath;
862+
let resolvedName: string = host.resolveExternalModule(moduleName, searchPath);
863+
if (resolvedName) {
864+
sourceFile = host.getSourceFile(resolvedName);
873865
}
874866
if (sourceFile) {
875867
if (sourceFile.symbol) {

src/compiler/program.ts

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ module ts {
155155
let commonSourceDirectory: string;
156156
let diagnosticsProducingTypeChecker: TypeChecker;
157157
let noDiagnosticsTypeChecker: TypeChecker;
158+
let resolvedExternalModuleCache: Map<string> = {};
158159

159160
let start = new Date().getTime();
160161

@@ -184,6 +185,7 @@ module ts {
184185
getIdentifierCount: () => getDiagnosticsProducingTypeChecker().getIdentifierCount(),
185186
getSymbolCount: () => getDiagnosticsProducingTypeChecker().getSymbolCount(),
186187
getTypeCount: () => getDiagnosticsProducingTypeChecker().getTypeCount(),
188+
resolveExternalModule
187189
};
188190
return program;
189191

@@ -236,6 +238,60 @@ module ts {
236238
emitTime += new Date().getTime() - start;
237239
return emitResult;
238240
}
241+
242+
function resolveExternalModule(moduleName: string, searchPath: string): string {
243+
let cacheLookupName = moduleName + searchPath;
244+
if (resolvedExternalModuleCache[cacheLookupName]) {
245+
return resolvedExternalModuleCache[cacheLookupName];
246+
}
247+
if (resolvedExternalModuleCache[cacheLookupName] === '') {
248+
return undefined;
249+
}
250+
function getNameIfExists(fileName: string): string {
251+
if (sys.fileExists(fileName)) {
252+
return fileName;
253+
}
254+
}
255+
while (true) {
256+
// Look at files by all extensions
257+
let found = forEach(supportedExtensions,
258+
extension => getNameIfExists(normalizePath(combinePaths(searchPath, moduleName)) + extension));
259+
// Also look at all files by node_modules
260+
if (!found) {
261+
found = forEach(supportedExtensions,
262+
extension => getNameIfExists(normalizePath(combinePaths(combinePaths(searchPath, "node_modules"), moduleName)) + extension));
263+
}
264+
// Also look at package.json's main in node_modules
265+
if (!found) {
266+
// If we found a package.json then look at its main field
267+
let pkgJson = getNameIfExists(normalizePath(combinePaths(combinePaths(combinePaths(searchPath, "node_modules"), moduleName), "package.json")));
268+
if (pkgJson) {
269+
let pkgFile = JSON.parse(sys.readFile(pkgJson));
270+
if (pkgFile.main) {
271+
var indexFileName = removeFileExtension(combinePaths(getDirectoryPath(pkgJson), pkgFile.main));
272+
found = forEach(supportedExtensions,
273+
extension => getNameIfExists(indexFileName + extension))
274+
}
275+
}
276+
}
277+
// look at node_modules index
278+
if (!found) {
279+
found = forEach(supportedExtensions,
280+
extension => getNameIfExists(normalizePath(combinePaths(combinePaths(combinePaths(searchPath, "node_modules"), moduleName), "index")) + extension));
281+
}
282+
283+
// Finally cache and return or continue up the directory tree
284+
if (found) {
285+
return resolvedExternalModuleCache[cacheLookupName] = found;
286+
}
287+
let parentPath = getDirectoryPath(searchPath);
288+
if (parentPath === searchPath) {
289+
resolvedExternalModuleCache[cacheLookupName] = '';
290+
return undefined;
291+
}
292+
searchPath = parentPath;
293+
}
294+
}
239295

240296
function getSourceFile(fileName: string) {
241297
fileName = host.getCanonicalFileName(normalizeSlashes(fileName));
@@ -428,18 +484,9 @@ module ts {
428484
if (moduleNameExpr && moduleNameExpr.kind === SyntaxKind.StringLiteral) {
429485
let moduleNameText = (<LiteralExpression>moduleNameExpr).text;
430486
if (moduleNameText) {
431-
let searchPath = basePath;
432-
let searchName: string;
433-
while (true) {
434-
searchName = normalizePath(combinePaths(searchPath, moduleNameText));
435-
if (forEach(supportedExtensions, extension => findModuleSourceFile(searchName + extension, moduleNameExpr))) {
436-
break;
437-
}
438-
let parentPath = getDirectoryPath(searchPath);
439-
if (parentPath === searchPath) {
440-
break;
441-
}
442-
searchPath = parentPath;
487+
let resolvedName: string = resolveExternalModule(moduleNameText, getDirectoryPath(file.fileName));
488+
if (resolvedName) {
489+
findModuleSourceFile(resolvedName, moduleNameExpr);
443490
}
444491
}
445492
}

src/compiler/types.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1069,6 +1069,8 @@ module ts {
10691069
* Gets a type checker that can be used to semantically analyze source fils in the program.
10701070
*/
10711071
getTypeChecker(): TypeChecker;
1072+
1073+
resolveExternalModule(moduleName: string, basePath: string): string;
10721074

10731075
/* @internal */ getCommonSourceDirectory(): string;
10741076

@@ -1133,6 +1135,7 @@ module ts {
11331135
export interface TypeCheckerHost {
11341136
getCompilerOptions(): CompilerOptions;
11351137

1138+
resolveExternalModule(moduleName: string, basePath: string): string;
11361139
getSourceFiles(): SourceFile[];
11371140
getSourceFile(fileName: string): SourceFile;
11381141
}

0 commit comments

Comments
 (0)