I got tripped up when using the compiler API, and I wanted to see if it was just me being confused or an actual bug. :) It seems like SourceFiles that are returned from LanguageService.getSourceFile() don't include symbols, whereas those loaded via Program.getSourceFile() do.
If I request a file via:
languageService.getSourceFile("example.ts");...it will be returned without symbols, so if I try calling any of TypeChecker's methods on it, it will either throw errors or returned undefined. If instead I request files via:
languageService.getProgram().getSourceFile("example.ts");..the returned file has the symbols and works fine with TypeChecker.
I understand that mixing these two APIs is probably not a normal use case. I'm working on a tool that alters the source of a program as it's being compiled, so having access to LanguageService is really helpful, but I also need the TypeChecker.
(Also, if this is just a problem with my implementation of LanguageServiceHost, please let me know!)
TypeScript Version: Behavior appears on 1.8.7, 1.8.9, and 1.9.0-dev.20160318
Test Case
test.ts
import*astsfrom'typescript';import*asfsfrom'fs';interfaceScriptInfo{text: stringversion: number}exportclassLanguageServiceHostimplementsts.LanguageServiceHost{files: {[name: string]: ScriptInfo}={};constructor(protectedrootFileNames: string[],protectedoptions: ts.CompilerOptions){for(constfileNameofrootFileNames){this.getScriptInfo(fileName);}}getCompilationSettings(){returnthis.options;}getScriptFileNames(){returnthis.rootFileNames;}getScriptVersion(fileName: string){letinfo=this.getScriptInfo(fileName);returninfo.version.toString();}getScriptSnapshot(fileName: string){letinfo=this.getScriptInfo(fileName);returnts.ScriptSnapshot.fromString(info.text);}getCurrentDirectory(){returnprocess.cwd();}getDefaultLibFileName(options: ts.CompilerOptions){returnts.getDefaultLibFilePath(options);}getScriptInfo(fileName: string): ScriptInfo{letinfo=this.files[fileName];if(!info){this.files[fileName]=info={text: fs.readFileSync(fileName).toString(),version: 1};}returninfo;}}constlanguageServiceHost=newLanguageServiceHost(['case.ts'],{target: ts.ScriptTarget.ES5,module: ts.ModuleKind.CommonJS});constlanguageService=ts.createLanguageService(languageServiceHost,ts.createDocumentRegistry());constprogram=languageService.getProgram();constchecker=program.getTypeChecker();functionlistClassMethods(file: ts.SourceFile){letvisit=(node: ts.Node)=>{if(node.kind==ts.SyntaxKind.ClassDeclaration){constdecl=<ts.ClassDeclaration>node;for(constmemberofdecl.members){if(member.kind==ts.SyntaxKind.MethodDeclaration){constmethod=<ts.MethodDeclaration>member;constsymbol=checker.getSymbolAtLocation(method.name);if(symbol){console.log(symbol.getName());}else{console.log("Couldn't resolve symbol")}}}}ts.forEachChild(node,visit);}ts.forEachChild(file,visit);}listClassMethods(languageService.getSourceFile('case.ts'));listClassMethods(program.getSourceFile('case.ts'));case.ts
interfaceIExample{getName: ()=>string}classAimplementsIExample{getName(){return'A';}}classBimplementsIExample{getName(){return'B';}}Expected behavior:
$ node test.js
getName
getName
getName
getName
Actual behavior:
$ node test.js
Couldn't resolve symbol
Couldn't resolve symbol
getName
getName
Thanks for your help, and for the great work on TypeScript and the compiler API!
I got tripped up when using the compiler API, and I wanted to see if it was just me being confused or an actual bug. :) It seems like
SourceFiles that are returned fromLanguageService.getSourceFile()don't include symbols, whereas those loaded viaProgram.getSourceFile()do.If I request a file via:
...it will be returned without symbols, so if I try calling any of
TypeChecker's methods on it, it will either throw errors or returnedundefined. If instead I request files via:..the returned file has the symbols and works fine with
TypeChecker.I understand that mixing these two APIs is probably not a normal use case. I'm working on a tool that alters the source of a program as it's being compiled, so having access to
LanguageServiceis really helpful, but I also need theTypeChecker.(Also, if this is just a problem with my implementation of
LanguageServiceHost, please let me know!)TypeScript Version: Behavior appears on 1.8.7, 1.8.9, and 1.9.0-dev.20160318
Test Case
test.ts
case.ts
Expected behavior:
Actual behavior:
Thanks for your help, and for the great work on TypeScript and the compiler API!