alm
Version:
The best IDE for TypeScript
130 lines (111 loc) • 4.94 kB
text/typescript
import path = require('path');
import tsconfig = require('./tsconfig');
import {selectMany,createMap} from "../../../../common/utils";
import * as types from "../../../../common/types";
import * as typescriptDir from "./typeScriptDir";
import * as utils from "../../../../common/utils";
import { LanguageServiceHost } from '../../../../languageServiceHost/languageServiceHostNode';
import {master as masterType} from "../projectServiceContract";
let master: typeof masterType;
export function setMaster(m: typeof masterType) {
master = m;
}
/**
* Wraps up `langaugeService` `languageServiceHost` and `projectFile` in a single package
*/
export class Project {
public languageServiceHost: LanguageServiceHost;
public languageService: ts.LanguageService;
public configFile: types.TypeScriptConfigFileDetails;
constructor(projectData: types.ProjectDataLoaded) {
this.configFile = projectData.configFile;
this.languageServiceHost
= new LanguageServiceHost(projectData.configFile.projectFilePath, projectData.configFile.project.compilerOptions)
.addAlmDemo();
// Add all the files
projectData.filePathWithContents.forEach(({filePath,contents}) => {
this.languageServiceHost.addScript(filePath, contents);
});
this.languageServiceHost.incrementallyAddedFile.on((data)=>{
// console.log(data); // DEBUG
master.receiveIncrementallyAddedFile(data)
});
this.languageService = ts.createLanguageService(this.languageServiceHost, ts.createDocumentRegistry());
}
public getAllSourceFiles(): ts.SourceFile[] {
return this.languageService.getProgram().getSourceFiles().concat();
}
/**
* all files
* - except lib.d.ts
* - And files in `node_modules
* Note: this function is exceedingly slow on cold boot (13s on vscode codebase) as it calls getProgram.getSourceFiles
*/
public getProjectSourceFiles(): ts.SourceFile[] {
var libFileLookup = createMap(typescriptDir.getDefaultLibFilePaths(this.configFile.project.compilerOptions));
var files
= this.getAllSourceFiles().filter(x=> !libFileLookup[x.fileName]);
return files;
}
public getSourceFile(filePath: string): ts.SourceFile | undefined {
return this.getAllSourceFiles().find(f => f.fileName === filePath);
}
public includesSourceFile(filePath: string) {
return (this.getAllSourceFiles().filter((f) => f.fileName === filePath).length === 1);
}
/**
* Gets all the files in the project that are not `.json` files
*/
public getFilePaths(): string[]{
return (this.configFile.project.files).filter(f=>!f.endsWith('.json'));
}
public getDiagnosticsForFile(filePath: string) {
var diagnostics = this.languageService.getSyntacticDiagnostics(filePath);
if (diagnostics.length === 0) {
if (this.configFile.project.compilerOptions.skipLibCheck && filePath.endsWith('.d.ts')) {
// Nothing to do
}
else {
diagnostics = this.languageService.getSemanticDiagnostics(filePath);
}
}
return diagnostics;
}
public getDiagnostics(cancellationToken: utils.CancellationToken): Promise<ts.Diagnostic[]> {
const program = this.languageService.getProgram();
return new Promise<ts.Diagnostic[]>((resolve, reject) => {
let allDiagnostics: ts.Diagnostic[] = [];
allDiagnostics = program.getGlobalDiagnostics().concat();
const sourceFiles = program.getSourceFiles().concat();
utils
.cancellableForEach({
cancellationToken,
items: sourceFiles,
cb: (sourceFile) => {
ts.addRange(allDiagnostics, program.getSyntacticDiagnostics(sourceFile));
},
})
.then(() => {
return utils.cancellableForEach({
cancellationToken,
items: sourceFiles,
cb: (sourceFile) => {
if (this.configFile.project.compilerOptions.skipLibCheck && sourceFile.isDeclarationFile) {
// Nothing to do
}
else {
ts.addRange(allDiagnostics, program.getSemanticDiagnostics(sourceFile));
}
},
});
})
.then(() => {
allDiagnostics = ts.sortAndDeduplicateDiagnostics(allDiagnostics);
resolve(allDiagnostics);
})
.catch((res) => {
reject(res);
});
});
}
}