99// the APACHE 2.0 license. Some utility functions and
1010// TypeScript were also lifted.
1111
12+ import * as path from 'path' ;
13+ import * as fs from 'fs' ;
1214import * as ts from 'typescript' ;
1315import * as ng from '@angular/language-service' ;
1416
@@ -799,21 +801,22 @@ export class Project {
799801
800802 constructor (
801803 public projectService : ProjectService ,
804+ private logger : Logger ,
802805 public projectOptions ?: ProjectOptions ,
803806 public languageServiceDiabled = false ) {
804807 if ( projectOptions && projectOptions . files ) {
805808 // If files are listed explicitly, allow all extensions
806809 projectOptions . compilerOptions [ 'allowNonTsExtensions' ] = true ;
807810 }
808811 if ( ! languageServiceDiabled ) {
809- this . compilerService = new CompilerService ( this , projectOptions && projectOptions . compilerOptions ) ;
812+ this . compilerService = new CompilerService ( this , logger , projectOptions && projectOptions . compilerOptions ) ;
810813 }
811814 }
812815
813816 enableLanguageService ( ) {
814817 // if the language service was disabled, we should re-initiate the compiler service
815818 if ( this . languageServiceDiabled ) {
816- this . compilerService = new CompilerService ( this , this . projectOptions && this . projectOptions . compilerOptions ) ;
819+ this . compilerService = new CompilerService ( this , this . logger , this . projectOptions && this . projectOptions . compilerOptions ) ;
817820 }
818821 this . languageServiceDiabled = false ;
819822 }
@@ -1072,16 +1075,6 @@ export class ProjectService {
10721075 } ;
10731076 }
10741077
1075- // getFormatCodeOptions(file?: string) {
1076- // if (file) {
1077- // const info = this.filenameToScriptInfo[file];
1078- // if (info) {
1079- // return info.formatCodeOptions;
1080- // }
1081- // }
1082- // return this.hostConfiguration.formatCodeOptions;
1083- // }
1084-
10851078 watchedFileChanged ( fileName : string ) {
10861079 const info = this . filenameToScriptInfo [ fileName ] ;
10871080 if ( ! info ) {
@@ -1210,32 +1203,12 @@ export class ProjectService {
12101203 this . psLogger . msg ( msg , type ) ;
12111204 }
12121205
1213- // setHostConfiguration(args: ts.server.protocol.ConfigureRequestArguments) {
1214- // if (args.file) {
1215- // const info = this.filenameToScriptInfo[args.file];
1216- // if (info) {
1217- // info.setFormatOptions(args.formatOptions);
1218- // this.log("Host configuration update for file " + args.file, "Info");
1219- // }
1220- // }
1221- // else {
1222- // if (args.hostInfo !== undefined) {
1223- // this.hostConfiguration.hostInfo = args.hostInfo;
1224- // this.log("Host information " + args.hostInfo, "Info");
1225- // }
1226- // if (args.formatOptions) {
1227- // mergeFormatOptions(this.hostConfiguration.formatCodeOptions, args.formatOptions);
1228- // this.log("Format host information updated", "Info");
1229- // }
1230- // }
1231- // }
1232-
12331206 closeLog ( ) {
12341207 this . psLogger . close ( ) ;
12351208 }
12361209
12371210 createInferredProject ( root : ScriptInfo ) {
1238- const project = new Project ( this ) ;
1211+ const project = new Project ( this , this . psLogger ) ;
12391212 project . addRoot ( root ) ;
12401213
12411214 let currentPath = getDirectoryPath ( root . fileName ) ;
@@ -1867,53 +1840,20 @@ export class ProjectService {
18671840 }
18681841 }
18691842
1870- // private exceedTotalNonTsFileSizeLimit(fileNames: string[]) {
1871- // let totalNonTsFileSize = 0;
1872- // if (!this.host.getFileSize) {
1873- // return false;
1874- // }
1875-
1876- // for (const fileName of fileNames) {
1877- // if (hasTypeScriptFileExtension(fileName)) {
1878- // continue;
1879- // }
1880- // totalNonTsFileSize += this.host.getFileSize(fileName);
1881- // if (totalNonTsFileSize > maxProgramSizeForNonTsFiles) {
1882- // return true;
1883- // }
1884- // }
1885- // return false;
1886- // }
1887-
18881843 openConfigFile ( configFilename : string , clientFileName ?: string ) : { project ?: Project , errors : ts . Diagnostic [ ] } {
18891844 const parseConfigFileResult = this . configFileToProjectOptions ( configFilename ) ;
18901845 let errors = parseConfigFileResult . errors ;
18911846 if ( ! parseConfigFileResult . projectOptions ) {
18921847 return { errors } ;
18931848 }
18941849 const projectOptions = parseConfigFileResult . projectOptions ;
1895- // if (!projectOptions.compilerOptions.disableSizeLimit && projectOptions.compilerOptions.allowJs) {
1896- // if (this.exceedTotalNonTsFileSizeLimit(projectOptions.files)) {
1897- // const project = this.createProject(configFilename, projectOptions, /*languageServiceDisabled*/ true);
1898-
1899- // // for configured projects with languageService disabled, we only watch its config file,
1900- // // do not care about the directory changes in the folder.
1901- // project.projectFileWatcher = this.host.watchFile(
1902- // toPath(configFilename, configFilename, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)),
1903- // _ => this.watchedProjectConfigFileChanged(project));
1904- // return { project, errors };
1905- // }
1906- // }
19071850
19081851 const project = this . createProject ( configFilename , projectOptions ) ;
19091852 for ( const rootFilename of projectOptions . files ) {
19101853 if ( this . host . fileExists ( rootFilename ) ) {
19111854 const info = this . openFile ( rootFilename , /*openedByClient*/ clientFileName == rootFilename ) ;
19121855 project . addRoot ( info ) ;
19131856 }
1914- else {
1915- // (errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.File_0_not_found, rootFilename));
1916- }
19171857 }
19181858 project . finishGraph ( ) ;
19191859 project . projectFileWatcher = this . host . watchFile ( configFilename , _ => this . watchedProjectConfigFileChanged ( project ) ) ;
@@ -1955,19 +1895,6 @@ export class ProjectService {
19551895 return errors ;
19561896 }
19571897 else {
1958- // if (projectOptions.compilerOptions && !projectOptions.compilerOptions.disableSizeLimit && this.exceedTotalNonTsFileSizeLimit(projectOptions.files)) {
1959- // project.setProjectOptions(projectOptions);
1960- // if (project.languageServiceDiabled) {
1961- // return errors;
1962- // }
1963-
1964- // project.disableLanguageService();
1965- // if (project.directoryWatcher) {
1966- // project.directoryWatcher.close();
1967- // project.directoryWatcher = undefined;
1968- // }
1969- // return errors;
1970- // }
19711898
19721899 if ( project . languageServiceDiabled ) {
19731900 project . setProjectOptions ( projectOptions ) ;
@@ -2036,7 +1963,7 @@ export class ProjectService {
20361963 }
20371964
20381965 createProject ( projectFilename : string , projectOptions ?: ProjectOptions , languageServiceDisabled ?: boolean ) {
2039- const project = new Project ( this , projectOptions , languageServiceDisabled ) ;
1966+ const project = new Project ( this , this . psLogger , projectOptions , languageServiceDisabled ) ;
20401967 project . projectFilename = projectFilename ;
20411968 return project ;
20421969 }
@@ -2051,8 +1978,9 @@ export class CompilerService {
20511978 classifier : ts . Classifier ;
20521979 settings : ts . CompilerOptions ;
20531980 documentRegistry = ts . createDocumentRegistry ( ) ;
1981+ ng : typeof ng ;
20541982
2055- constructor ( public project : Project , opt ?: ts . CompilerOptions ) {
1983+ constructor ( public project : Project , private logger : Logger , opt ?: ts . CompilerOptions ) {
20561984 this . host = new LSHost ( project . projectService . host , project ) ;
20571985 if ( opt ) {
20581986 this . setCompilerOptions ( opt ) ;
@@ -2063,9 +1991,13 @@ export class CompilerService {
20631991 defaultOpts . allowJs = true ;
20641992 this . setCompilerOptions ( defaultOpts ) ;
20651993 }
1994+
1995+
20661996 this . languageService = ts . createLanguageService ( this . host , this . documentRegistry ) ;
2067- this . ngHost = new ng . TypeScriptServiceHost ( ts , this . host , this . languageService ) ;
2068- this . ngService = ng . createLanguageService ( this . ngHost ) ;
1997+
1998+ this . ng = this . resolveLanguageServiceModule ( ) ;
1999+ this . ngHost = new this . ng . TypeScriptServiceHost ( ts , this . host , this . languageService ) ;
2000+ this . ngService = this . ng . createLanguageService ( this . ngHost ) ;
20692001 this . ngHost . setSite ( this . ngService ) ;
20702002 this . classifier = ts . createClassifier ( ) ;
20712003 }
@@ -2080,6 +2012,29 @@ export class CompilerService {
20802012 return ts . isExternalModule ( sourceFile ) ;
20812013 }
20822014
2015+ resolveLanguageServiceModule ( ) : typeof ng {
2016+ const host = path . resolve ( this . host . getCurrentDirectory ( ) , 'main.ts' ) ;
2017+ const modules = this . host . resolveModuleNames ( [ '@angular/language-service' ] , host ) ;
2018+ if ( modules && modules [ 0 ] ) {
2019+ const resolvedModule = modules [ 0 ] ;
2020+ const moduleName = path . dirname ( resolvedModule . resolvedFileName ) ;
2021+ if ( fs . existsSync ( moduleName ) ) {
2022+ try {
2023+ const result : typeof ng = require ( moduleName ) ;
2024+ if ( result ) return result ;
2025+ } catch ( e ) {
2026+ this . log ( `Error loading module "${ moduleName } "; using local language service instead` ) ;
2027+ this . log ( e . stack ) ;
2028+ }
2029+ }
2030+ }
2031+ return ng ;
2032+ }
2033+
2034+ private log ( message : string ) {
2035+ return this . logger . msg ( message ) ;
2036+ }
2037+
20832038 static getDefaultFormatCodeOptions ( host : ProjectServiceHost ) : ts . FormatCodeOptions {
20842039 return clone ( {
20852040 BaseIndentSize : 0 ,
0 commit comments