diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 2ebf086cb74..121d1938a4a 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -285,7 +285,9 @@ module FourSlash { case FourSlashTestType.Native: return new Harness.LanguageService.NativeLanugageServiceAdapter(cancellationToken, compilationOptions); case FourSlashTestType.Shims: - return new Harness.LanguageService.ShimLanugageServiceAdapter(cancellationToken, compilationOptions); + return new Harness.LanguageService.ShimLanugageServiceAdapter(/*preprocessToResolve*/ false, cancellationToken, compilationOptions); + case FourSlashTestType.ShimsWithPreprocess: + return new Harness.LanguageService.ShimLanugageServiceAdapter(/*preprocessToResolve*/ true, cancellationToken, compilationOptions); case FourSlashTestType.Server: return new Harness.LanguageService.ServerLanugageServiceAdapter(cancellationToken, compilationOptions); default: diff --git a/src/harness/fourslashRunner.ts b/src/harness/fourslashRunner.ts index 3914232dbe8..d30a30d88e3 100644 --- a/src/harness/fourslashRunner.ts +++ b/src/harness/fourslashRunner.ts @@ -5,6 +5,7 @@ const enum FourSlashTestType { Native, Shims, + ShimsWithPreprocess, Server } @@ -23,6 +24,10 @@ class FourSlashRunner extends RunnerBase { this.basePath = "tests/cases/fourslash/shims"; this.testSuiteName = "fourslash-shims"; break; + case FourSlashTestType.ShimsWithPreprocess: + this.basePath = 'tests/cases/fourslash/shims-pp'; + this.testSuiteName = 'fourslash-shims-pp'; + break; case FourSlashTestType.Server: this.basePath = "tests/cases/fourslash/server"; this.testSuiteName = "fourslash-server"; diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index f33562a5a2f..db388c95610 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -203,9 +203,35 @@ module Harness.LanguageService { /// Shim adapter class ShimLanguageServiceHost extends LanguageServiceAdapterHost implements ts.LanguageServiceShimHost, ts.CoreServicesShimHost { private nativeHost: NativeLanguageServiceHost; - constructor(cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) { + + public getModuleResolutionsForFile: (fileName: string)=> string; + + constructor(preprocessToResolve: boolean, cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) { super(cancellationToken, options); this.nativeHost = new NativeLanguageServiceHost(cancellationToken, options); + + if (preprocessToResolve) { + let compilerOptions = this.nativeHost.getCompilationSettings() + let moduleResolutionHost: ts.ModuleResolutionHost = { + fileExists: fileName => this.getScriptInfo(fileName) !== undefined, + readFile: fileName => { + let scriptInfo = this.getScriptInfo(fileName); + return scriptInfo && scriptInfo.content; + } + }; + this.getModuleResolutionsForFile = (fileName) => { + let scriptInfo = this.getScriptInfo(fileName); + let preprocessInfo = ts.preProcessFile(scriptInfo.content, /*readImportFiles*/ true); + let imports: ts.Map = {}; + for (let module of preprocessInfo.importedFiles) { + let resolutionInfo = ts.resolveModuleName(module.fileName, fileName, compilerOptions, moduleResolutionHost); + if (resolutionInfo.resolvedFileName) { + imports[module.fileName] = resolutionInfo.resolvedFileName; + } + } + return JSON.stringify(imports); + } + } } getFilenames(): string[] { return this.nativeHost.getFilenames(); } @@ -228,7 +254,7 @@ module Harness.LanguageService { readDirectory(rootDir: string, extension: string): string { throw new Error("NYI"); - } + } fileExists(fileName: string) { return this.getScriptInfo(fileName) !== undefined; } readFile(fileName: string) { let snapshot = this.nativeHost.getScriptSnapshot(fileName); @@ -400,8 +426,8 @@ module Harness.LanguageService { export class ShimLanugageServiceAdapter implements LanguageServiceAdapter { private host: ShimLanguageServiceHost; private factory: ts.TypeScriptServicesFactory; - constructor(cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) { - this.host = new ShimLanguageServiceHost(cancellationToken, options); + constructor(preprocessToResolve: boolean, cancellationToken?: ts.HostCancellationToken, options?: ts.CompilerOptions) { + this.host = new ShimLanguageServiceHost(preprocessToResolve, cancellationToken, options); this.factory = new TypeScript.Services.TypeScriptServicesFactory(); } getHost() { return this.host; } diff --git a/src/harness/runner.ts b/src/harness/runner.ts index 06aaf3d32b5..3d97938011c 100644 --- a/src/harness/runner.ts +++ b/src/harness/runner.ts @@ -68,7 +68,10 @@ if (testConfigFile !== "") { case "fourslash-shims": runners.push(new FourSlashRunner(FourSlashTestType.Shims)); break; - case "fourslash-server": + case 'fourslash-shims-pp': + runners.push(new FourSlashRunner(FourSlashTestType.ShimsWithPreprocess)); + break; + case 'fourslash-server': runners.push(new FourSlashRunner(FourSlashTestType.Server)); break; case "fourslash-generated": @@ -98,6 +101,7 @@ if (runners.length === 0) { // language services runners.push(new FourSlashRunner(FourSlashTestType.Native)); runners.push(new FourSlashRunner(FourSlashTestType.Shims)); + runners.push(new FourSlashRunner(FourSlashTestType.ShimsWithPreprocess)); runners.push(new FourSlashRunner(FourSlashTestType.Server)); // runners.push(new GeneratedFourslashRunner()); } diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 82621db291a..eec7d475890 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -200,6 +200,7 @@ namespace ts.server { removeReferencedFile(info: ScriptInfo) { if (!info.isOpen) { this.filenameToScript[info.fileName] = undefined; + this.resolvedModuleNames.remove(info.fileName); } } diff --git a/src/services/shims.ts b/src/services/shims.ts index f203dc6cbc4..1512c5df523 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -61,7 +61,7 @@ namespace ts { getProjectVersion?(): string; useCaseSensitiveFileNames?(): boolean; - getModuleResolutionsForFile?(fileName: string): string; + getModuleResolutionsForFile?(fileName: string): string; } /** Public interface of the the of a config service shim instance.*/ diff --git a/tests/cases/unittests/services/colorization.ts b/tests/cases/unittests/services/colorization.ts index da1fa91036c..82f2e106aa4 100644 --- a/tests/cases/unittests/services/colorization.ts +++ b/tests/cases/unittests/services/colorization.ts @@ -9,8 +9,8 @@ interface ClassificationEntry { describe('Colorization', function () { // Use the shim adapter to ensure test coverage of the shim layer for the classifier - var languageServiceAdabtor = new Harness.LanguageService.ShimLanugageServiceAdapter(); - var classifier = languageServiceAdabtor.getClassifier(); + var languageServiceAdapter = new Harness.LanguageService.ShimLanugageServiceAdapter(/*preprocessToResolve*/ false); + var classifier = languageServiceAdapter.getClassifier(); function getEntryAtPosistion(result: ts.ClassificationResult, position: number) { var entryPosition = 0;