Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,10 @@ namespace ts {
},
description: Diagnostics.Specify_library_files_to_be_included_in_the_compilation_Colon
},
{
name: "disableProjectSizeLimit",
type: "boolean"
},
{
name: "strictNullChecks",
type: "boolean",
Expand Down Expand Up @@ -761,8 +765,10 @@ namespace ts {
}
}

filesSeen[fileName] = true;
fileNames.push(fileName);
if (!filesSeen[fileName]) {
filesSeen[fileName] = true;
fileNames.push(fileName);
}
}
}
}
Expand Down
15 changes: 13 additions & 2 deletions src/compiler/sys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace ts {
useCaseSensitiveFileNames: boolean;
write(s: string): void;
readFile(path: string, encoding?: string): string;
getFileSize?(path: string): number;
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
Expand Down Expand Up @@ -79,7 +80,7 @@ namespace ts {
realpath(path: string): string;
};

export var sys: System = (function () {
export var sys: System = (function() {

function getWScriptSystem(): System {

Expand Down Expand Up @@ -503,7 +504,7 @@ namespace ts {
}
);
},
resolvePath: function (path: string): string {
resolvePath: function(path: string): string {
return _path.resolve(path);
},
fileExists,
Expand Down Expand Up @@ -540,6 +541,16 @@ namespace ts {
}
return process.memoryUsage().heapUsed;
},
getFileSize(path) {
try {
const stat = _fs.statSync(path);
if (stat.isFile()) {
return stat.size;
}
}
catch (e) { }
return 0;
},
exit(exitCode?: number): void {
process.exit(exitCode);
},
Expand Down
1 change: 1 addition & 0 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2562,6 +2562,7 @@ namespace ts {
/* @internal */ suppressOutputPathCheck?: boolean;
target?: ScriptTarget;
traceResolution?: boolean;
disableSizeLimit?: boolean;
types?: string[];
/** Paths used to used to compute primary types search locations */
typeRoots?: string[];
Expand Down
4 changes: 4 additions & 0 deletions src/compiler/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2714,6 +2714,10 @@ namespace ts {
return forEach(supportedJavascriptExtensions, extension => fileExtensionIs(fileName, extension));
}

export function hasTypeScriptFileExtension(fileName: string) {
return forEach(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension));
}

/**
* Replace each instance of non-ascii characters by one, two, three, or four escape sequences
* representing the UTF-8 encoding of the character, and return the expanded char code list.
Expand Down
164 changes: 157 additions & 7 deletions src/server/editorServices.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ namespace ts.server {
});
}

export const maxProgramSizeForNonTsFiles = 20 * 1024 * 1024;

export class ScriptInfo {
svc: ScriptVersionCache;
children: ScriptInfo[] = []; // files referenced by this file
Expand Down Expand Up @@ -385,12 +387,29 @@ namespace ts.server {
/** Used for configured projects which may have multiple open roots */
openRefCount = 0;

constructor(public projectService: ProjectService, public projectOptions?: ProjectOptions) {
constructor(
public projectService: ProjectService,
public projectOptions?: ProjectOptions,
public languageServiceDiabled = false) {
if (projectOptions && projectOptions.files) {
// If files are listed explicitly, allow all extensions
projectOptions.compilerOptions.allowNonTsExtensions = true;
}
this.compilerService = new CompilerService(this, projectOptions && projectOptions.compilerOptions);
if (!languageServiceDiabled) {
this.compilerService = new CompilerService(this, projectOptions && projectOptions.compilerOptions);
}
}

enableLanguageService() {
// if the language service was disabled, we should re-initiate the compiler service
if (this.languageServiceDiabled) {
this.compilerService = new CompilerService(this, this.projectOptions && this.projectOptions.compilerOptions);
}
this.languageServiceDiabled = false;
}

disableLanguageService() {
this.languageServiceDiabled = true;
}

addOpenRef() {
Expand All @@ -407,19 +426,45 @@ namespace ts.server {
}

getRootFiles() {
if (this.languageServiceDiabled) {
// When the languageService was disabled, only return file list if it is a configured project
return this.projectOptions ? this.projectOptions.files : undefined;
}

return this.compilerService.host.roots.map(info => info.fileName);
}

getFileNames() {
if (this.languageServiceDiabled) {
if (!this.projectOptions) {
return undefined;
}

const fileNames: string[] = [];
if (this.projectOptions && this.projectOptions.compilerOptions) {
fileNames.push(getDefaultLibFilePath(this.projectOptions.compilerOptions));
}
ts.addRange(fileNames, this.projectOptions.files);
return fileNames;
}

const sourceFiles = this.program.getSourceFiles();
return sourceFiles.map(sourceFile => sourceFile.fileName);
}

getSourceFile(info: ScriptInfo) {
if (this.languageServiceDiabled) {
return undefined;
}

return this.filenameToSourceFile[info.fileName];
}

getSourceFileFromName(filename: string, requireOpen?: boolean) {
if (this.languageServiceDiabled) {
return undefined;
}

const info = this.projectService.getScriptInfo(filename);
if (info) {
if ((!requireOpen) || info.isOpen) {
Expand All @@ -429,15 +474,27 @@ namespace ts.server {
}

isRoot(info: ScriptInfo) {
if (this.languageServiceDiabled) {
return undefined;
}

return this.compilerService.host.roots.some(root => root === info);
}

removeReferencedFile(info: ScriptInfo) {
if (this.languageServiceDiabled) {
return;
}

this.compilerService.host.removeReferencedFile(info);
this.updateGraph();
}

updateFileMap() {
if (this.languageServiceDiabled) {
return;
}

this.filenameToSourceFile = {};
const sourceFiles = this.program.getSourceFiles();
for (let i = 0, len = sourceFiles.length; i < len; i++) {
Expand All @@ -447,11 +504,19 @@ namespace ts.server {
}

finishGraph() {
if (this.languageServiceDiabled) {
return;
}

this.updateGraph();
this.compilerService.languageService.getNavigateToItems(".*");
}

updateGraph() {
if (this.languageServiceDiabled) {
return;
}

this.program = this.compilerService.languageService.getProgram();
this.updateFileMap();
}
Expand All @@ -462,15 +527,32 @@ namespace ts.server {

// add a root file to project
addRoot(info: ScriptInfo) {
if (this.languageServiceDiabled) {
return;
}

this.compilerService.host.addRoot(info);
}

// remove a root file from project
removeRoot(info: ScriptInfo) {
if (this.languageServiceDiabled) {
return;
}

this.compilerService.host.removeRoot(info);
}

filesToString() {
if (this.languageServiceDiabled) {
if (this.projectOptions) {
let strBuilder = "";
ts.forEach(this.projectOptions.files,
file => { strBuilder += file + "\n"; });
return strBuilder;
}
}

let strBuilder = "";
ts.forEachValue(this.filenameToSourceFile,
sourceFile => { strBuilder += sourceFile.fileName + "\n"; });
Expand All @@ -481,7 +563,9 @@ namespace ts.server {
this.projectOptions = projectOptions;
if (projectOptions.compilerOptions) {
projectOptions.compilerOptions.allowNonTsExtensions = true;
this.compilerService.setCompilerOptions(projectOptions.compilerOptions);
if (!this.languageServiceDiabled) {
this.compilerService.setCompilerOptions(projectOptions.compilerOptions);
}
}
}
}
Expand Down Expand Up @@ -1261,7 +1345,24 @@ namespace ts.server {
return { succeeded: true, projectOptions };
}
}
}

private exceedTotalNonTsFileSizeLimit(fileNames: string[]) {
let totalNonTsFileSize = 0;
if (!this.host.getFileSize) {
return false;
}

for (const fileName of fileNames) {
if (hasTypeScriptFileExtension(fileName)) {
continue;
}
totalNonTsFileSize += this.host.getFileSize(fileName);
if (totalNonTsFileSize > maxProgramSizeForNonTsFiles) {
return true;
}
}
return false;
}

openConfigFile(configFilename: string, clientFileName?: string): { success: boolean, project?: Project, errors?: Diagnostic[] } {
Expand All @@ -1270,6 +1371,19 @@ namespace ts.server {
return { success: false, errors };
}
else {
if (!projectOptions.compilerOptions.disableSizeLimit && projectOptions.compilerOptions.allowJs) {
if (this.exceedTotalNonTsFileSizeLimit(projectOptions.files)) {
const project = this.createProject(configFilename, projectOptions, /*languageServiceDisabled*/ true);

// for configured projects with languageService disabled, we only watch its config file,
// do not care about the directory changes in the folder.
project.projectFileWatcher = this.host.watchFile(
toPath(configFilename, configFilename, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)),
_ => this.watchedProjectConfigFileChanged(project));
return { success: true, project };
}
}

const project = this.createProject(configFilename, projectOptions);
let errors: Diagnostic[];
for (const rootFilename of projectOptions.files) {
Expand All @@ -1293,7 +1407,7 @@ namespace ts.server {
}
}

updateConfiguredProject(project: Project) {
updateConfiguredProject(project: Project): Diagnostic[] {
if (!this.host.fileExists(project.projectFilename)) {
this.log("Config file deleted");
this.removeProject(project);
Expand All @@ -1304,7 +1418,43 @@ namespace ts.server {
return errors;
}
else {
const oldFileNames = project.compilerService.host.roots.map(info => info.fileName);
if (projectOptions.compilerOptions && !projectOptions.compilerOptions.disableSizeLimit && this.exceedTotalNonTsFileSizeLimit(projectOptions.files)) {
project.setProjectOptions(projectOptions);
if (project.languageServiceDiabled) {
return;
}

project.disableLanguageService();
if (project.directoryWatcher) {
project.directoryWatcher.close();
project.directoryWatcher = undefined;
}
return;
}

if (project.languageServiceDiabled) {
project.setProjectOptions(projectOptions);
project.enableLanguageService();
project.directoryWatcher = this.host.watchDirectory(
ts.getDirectoryPath(project.projectFilename),
path => this.directoryWatchedForSourceFilesChanged(project, path),
/*recursive*/ true
);

for (const rootFilename of projectOptions.files) {
if (this.host.fileExists(rootFilename)) {
const info = this.openFile(rootFilename, /*openedByClient*/ false);
project.addRoot(info);
}
}
project.finishGraph();
return;
}

// if the project is too large, the root files might not have been all loaded if the total
// program size reached the upper limit. In that case project.projectOptions.files should
// be more precise. However this would only happen for configured project.
const oldFileNames = project.projectOptions ? project.projectOptions.files : project.compilerService.host.roots.map(info => info.fileName);
const newFileNames = ts.filter(projectOptions.files, f => this.host.fileExists(f));
const fileNamesToRemove = oldFileNames.filter(f => newFileNames.indexOf(f) < 0);
const fileNamesToAdd = newFileNames.filter(f => oldFileNames.indexOf(f) < 0);
Expand Down Expand Up @@ -1347,8 +1497,8 @@ namespace ts.server {
}
}

createProject(projectFilename: string, projectOptions?: ProjectOptions) {
const project = new Project(this, projectOptions);
createProject(projectFilename: string, projectOptions?: ProjectOptions, languageServiceDisabled?: boolean) {
const project = new Project(this, projectOptions, languageServiceDisabled);
project.projectFilename = projectFilename;
return project;
}
Expand Down
4 changes: 4 additions & 0 deletions src/server/protocol.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ declare namespace ts.server.protocol {
* The list of normalized file name in the project, including 'lib.d.ts'
*/
fileNames?: string[];
/**
* Indicates if the project has a active language service instance
*/
languageServiceDisabled?: boolean;
}

/**
Expand Down
Loading