mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-19 10:41:56 -05:00
resolveModuleName => resolvedModuleNames, added tests
This commit is contained in:
@@ -224,15 +224,17 @@ namespace ts {
|
||||
host = host || createCompilerHost(options);
|
||||
|
||||
// initialize resolveModuleNameWorker only if noResolve is false
|
||||
let resolveModuleNameWorker: (moduleName: string, containingFile: string) => string;
|
||||
let resolveModuleNamesWorker: (moduleNames: string[], containingFile: string) => string[];
|
||||
if (!options.noResolve) {
|
||||
resolveModuleNameWorker = host.resolveModuleName;
|
||||
if (!resolveModuleNameWorker) {
|
||||
resolveModuleNamesWorker = host.resolveModuleNames;
|
||||
if (!resolveModuleNamesWorker) {
|
||||
Debug.assert(host.getModuleResolutionHost !== undefined);
|
||||
let defaultResolver = getDefaultModuleNameResolver(options);
|
||||
resolveModuleNameWorker = (moduleName, containingFile) => {
|
||||
let moduleResolution = defaultResolver(moduleName, containingFile, options, host.getModuleResolutionHost());
|
||||
return moduleResolution.resolvedFileName;
|
||||
resolveModuleNamesWorker = (moduleNames, containingFile) => {
|
||||
return map(moduleNames, moduleName => {
|
||||
let moduleResolution = defaultResolver(moduleName, containingFile, options, host.getModuleResolutionHost());
|
||||
return moduleResolution.resolvedFileName;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -347,15 +349,16 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (resolveModuleNameWorker) {
|
||||
if (resolveModuleNamesWorker) {
|
||||
let moduleNames = map(newSourceFile.imports, name => name.text);
|
||||
let resolutions = resolveModuleNamesWorker(moduleNames, newSourceFile.fileName);
|
||||
// ensure that module resolution results are still correct
|
||||
for (let importName of newSourceFile.imports) {
|
||||
var oldResolution = getResolvedModuleFileName(oldSourceFile, importName.text);
|
||||
var newResolution = resolveModuleNameWorker(importName.text, newSourceFile.fileName);
|
||||
if (oldResolution !== newResolution) {
|
||||
for (let i = 0; i < moduleNames.length; ++i) {
|
||||
let oldResolution = getResolvedModuleFileName(oldSourceFile, moduleNames[i]);
|
||||
if (oldResolution !== resolutions[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// pass the cache of module resolutions from the old source file
|
||||
newSourceFile.resolvedModules = oldSourceFile.resolvedModules;
|
||||
@@ -719,10 +722,16 @@ namespace ts {
|
||||
if (file.imports.length) {
|
||||
file.resolvedModules = {};
|
||||
let oldSourceFile = oldProgram && oldProgram.getSourceFile(file.fileName);
|
||||
for (let moduleName of file.imports) {
|
||||
resolveModule(moduleName);
|
||||
}
|
||||
|
||||
let moduleNames = map(file.imports, name => name.text);
|
||||
let resolutions = resolveModuleNamesWorker(moduleNames, file.fileName);
|
||||
for (let i = 0; i < file.imports.length; ++i) {
|
||||
let resolution = resolutions[i];
|
||||
setResolvedModuleName(file, moduleNames[i], resolution);
|
||||
if (resolution) {
|
||||
findModuleSourceFile(resolution, file.imports[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// no imports - drop cached module resolutions
|
||||
@@ -733,16 +742,6 @@ namespace ts {
|
||||
function findModuleSourceFile(fileName: string, nameLiteral: Expression) {
|
||||
return findSourceFile(fileName, /* isDefaultLib */ false, file, nameLiteral.pos, nameLiteral.end - nameLiteral.pos);
|
||||
}
|
||||
|
||||
function resolveModule(moduleNameExpr: LiteralExpression): void {
|
||||
Debug.assert(resolveModuleNameWorker !== undefined);
|
||||
|
||||
let resolvedModuleName = resolveModuleNameWorker(moduleNameExpr.text, file.fileName);
|
||||
setResolvedModuleName(file, moduleNameExpr.text, resolvedModuleName);
|
||||
if (resolvedModuleName) {
|
||||
findModuleSourceFile(resolvedModuleName, moduleNameExpr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function computeCommonSourceDirectory(sourceFiles: SourceFile[]): string {
|
||||
|
||||
@@ -2266,7 +2266,7 @@ namespace ts {
|
||||
// if getModuleResolutionHost is implemented then compiler will apply one of built-in ways to resolve module names
|
||||
// and ModuleResolutionHost will be used to ask host specific questions
|
||||
// if resolveModuleName is implemented - this will mean that host is completely in charge of module name resolution
|
||||
resolveModuleName?(moduleName: string, containingFile: string): string;
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string): string[];
|
||||
getModuleResolutionHost?(): ModuleResolutionHost;
|
||||
}
|
||||
|
||||
|
||||
@@ -98,30 +98,54 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
resolveModuleName(moduleName: string, containingFile: string): string {
|
||||
let resolutionsInFile = this.resolvedModuleNames.get(containingFile);
|
||||
if (!resolutionsInFile) {
|
||||
resolutionsInFile = {};
|
||||
this.resolvedModuleNames.set(containingFile, resolutionsInFile);
|
||||
resolveModuleNames(moduleNames: string[], containingFile: string): string[] {
|
||||
let currentResolutionsInFile = this.resolvedModuleNames.get(containingFile);
|
||||
|
||||
let newResolutions: Map<TimestampedResolvedModule> = {};
|
||||
let resolvedFileNames: string[] = [];
|
||||
|
||||
let compilerOptions = this.getCompilationSettings();
|
||||
let defaultResolver = ts.getDefaultModuleNameResolver(compilerOptions);
|
||||
|
||||
for (let moduleName of moduleNames) {
|
||||
// check if this is a duplicate entry in the list
|
||||
let resolution = lookUp(newResolutions, moduleName);
|
||||
if (!resolution) {
|
||||
let existingResolution = currentResolutionsInFile && ts.lookUp(currentResolutionsInFile, moduleName);
|
||||
if (moduleResolutionIsValid(existingResolution)) {
|
||||
// ok, it is safe to use existing module resolution results
|
||||
resolution = existingResolution;
|
||||
}
|
||||
else {
|
||||
resolution = <TimestampedResolvedModule>defaultResolver(moduleName, containingFile, compilerOptions, this.moduleResolutionHost);
|
||||
resolution.lastCheckTime = Date.now();
|
||||
newResolutions[moduleName] = resolution;
|
||||
}
|
||||
}
|
||||
|
||||
ts.Debug.assert(resolution !== undefined);
|
||||
|
||||
resolvedFileNames.push(resolution.resolvedFileName);
|
||||
}
|
||||
|
||||
let resolution = ts.lookUp(resolutionsInFile, moduleName);
|
||||
if (!moduleResolutionIsValid(resolution)) {
|
||||
let compilerOptions = this.getCompilationSettings();
|
||||
let defaultResolver = ts.getDefaultModuleNameResolver(compilerOptions);
|
||||
resolution = <TimestampedResolvedModule>defaultResolver(moduleName, containingFile, compilerOptions, this.moduleResolutionHost);
|
||||
resolution.lastCheckTime = Date.now();
|
||||
resolutionsInFile[moduleName] = resolution;
|
||||
}
|
||||
return resolution.resolvedFileName;
|
||||
// replace old results with a new one
|
||||
this.resolvedModuleNames.set(containingFile, newResolutions);
|
||||
return resolvedFileNames;
|
||||
|
||||
function moduleResolutionIsValid(resolution: TimestampedResolvedModule): boolean {
|
||||
if (!resolution) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: use lastCheckTime assuming that module resolution results are legal for some period of time
|
||||
return !resolution.resolvedFileName && resolution.failedLookupLocations.length !== 0;
|
||||
if (resolution.resolvedFileName) {
|
||||
// TODO: consider checking failedLookupLocations
|
||||
// TODO: use lastCheckTime to track expiration for module name resolution
|
||||
return true;
|
||||
}
|
||||
|
||||
// consider situation if we have no candidate locations as valid resolution.
|
||||
// after all there is no point to invalidate it if we have no idea where to look for the module.
|
||||
return resolution.failedLookupLocations.length === 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -983,7 +983,7 @@ namespace ts {
|
||||
// if resolveModuleName is implemented - this will mean that host is completely in charge of module name resolution
|
||||
// if none of these methods are implemented then language service will try to emulate getModuleResolutionHost atop of 'getScriptSnapshot'
|
||||
getModuleResolutionHost?(): ModuleResolutionHost;
|
||||
resolveModuleName?(moduleName: string, containingFile: string): string;
|
||||
resolveModuleNames?(moduleNames: string[], containingFile: string): string[];
|
||||
}
|
||||
|
||||
//
|
||||
@@ -2564,7 +2564,8 @@ namespace ts {
|
||||
|
||||
let oldSettings = program && program.getCompilerOptions();
|
||||
let newSettings = hostCache.compilationSettings();
|
||||
let changesInCompilationSettingsAffectSyntax = oldSettings && oldSettings.target !== newSettings.target;
|
||||
let changesInCompilationSettingsAffectSyntax = oldSettings &&
|
||||
(oldSettings.target !== newSettings.target || oldSettings.module !== newSettings.module || oldSettings.noResolve !== newSettings.noResolve);
|
||||
|
||||
// Now create a new compiler
|
||||
let compilerHost: CompilerHost = {
|
||||
@@ -2578,8 +2579,8 @@ namespace ts {
|
||||
getCurrentDirectory: () => host.getCurrentDirectory(),
|
||||
};
|
||||
|
||||
if (host.resolveModuleName) {
|
||||
compilerHost.resolveModuleName = (moduleName, containingFile) => host.resolveModuleName(moduleName, containingFile)
|
||||
if (host.resolveModuleNames) {
|
||||
compilerHost.resolveModuleNames = (moduleNames, containingFile) => host.resolveModuleNames(moduleNames, containingFile)
|
||||
}
|
||||
else if (host.getModuleResolutionHost) {
|
||||
compilerHost.getModuleResolutionHost = () => host.getModuleResolutionHost()
|
||||
|
||||
@@ -267,22 +267,16 @@ namespace ts {
|
||||
private files: string[];
|
||||
private loggingEnabled = false;
|
||||
private tracingEnabled = false;
|
||||
private lastRequestedFile: string;
|
||||
private lastRequestedModuleResolutions: Map<string>;
|
||||
|
||||
public resolveModuleName: (moduleName: string, containingFile: string) => string;
|
||||
public resolveModuleNames: (moduleName: string[], containingFile: string) => string[];
|
||||
|
||||
constructor(private shimHost: LanguageServiceShimHost) {
|
||||
// if shimHost is a COM object then property check will become method call with no arguments.
|
||||
// 'in' does not have this effect.
|
||||
if ("getModuleResolutionsForFile" in this.shimHost) {
|
||||
this.resolveModuleName = (moduleName: string, containingFile: string) => {
|
||||
if (this.lastRequestedFile !== containingFile) {
|
||||
this.lastRequestedModuleResolutions = <Map<string>>JSON.parse(this.shimHost.getModuleResolutionsForFile(containingFile));
|
||||
this.lastRequestedFile = containingFile;
|
||||
}
|
||||
|
||||
return this.lastRequestedModuleResolutions[moduleName];
|
||||
this.resolveModuleNames = (moduleNames: string[], containingFile: string) => {
|
||||
let resolutionsInFile = <Map<string>>JSON.parse(this.shimHost.getModuleResolutionsForFile(containingFile));
|
||||
return map(moduleNames, name => lookUp(resolutionsInFile, name));
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user