diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts
index 6406455d713..682a434e6ab 100644
--- a/src/compiler/commandLineParser.ts
+++ b/src/compiler/commandLineParser.ts
@@ -5,12 +5,15 @@
///
namespace ts {
+ /* @internal */
+ export const compileOnSaveCommandLineOption: CommandLineOption = { name: "compileOnSave", type: "boolean" };
/* @internal */
export const optionDeclarations: CommandLineOption[] = [
{
name: "charset",
type: "string",
},
+ compileOnSaveCommandLineOption,
{
name: "declaration",
shortName: "d",
@@ -808,6 +811,7 @@ namespace ts {
options.configFilePath = configFileName;
const { fileNames, wildcardDirectories } = getFileNames(errors);
+ const compileOnSave = convertCompileOnSaveOptionFromJson(json, basePath, errors);
return {
options,
@@ -815,7 +819,8 @@ namespace ts {
typingOptions,
raw: json,
errors,
- wildcardDirectories
+ wildcardDirectories,
+ compileOnSave
};
function getFileNames(errors: Diagnostic[]): ExpandResult {
@@ -870,13 +875,24 @@ namespace ts {
}
}
+ export function convertCompileOnSaveOptionFromJson(jsonOption: any, basePath: string, errors: Diagnostic[]): boolean {
+ if (!hasProperty(jsonOption, compileOnSaveCommandLineOption.name)) {
+ return false;
+ }
+ const result = convertJsonOption(compileOnSaveCommandLineOption, jsonOption["compileOnSave"], basePath, errors);
+ if (typeof result === "boolean" && result) {
+ return result;
+ }
+ return false;
+ }
+
export function convertCompilerOptionsFromJson(jsonOptions: any, basePath: string, configFileName?: string): { options: CompilerOptions, errors: Diagnostic[] } {
const errors: Diagnostic[] = [];
const options = convertCompilerOptionsFromJsonWorker(jsonOptions, basePath, errors, configFileName);
return { options, errors };
}
- export function convertTypingOptionsFromJson(jsonOptions: any, basePath: string, configFileName?: string): { options: CompilerOptions, errors: Diagnostic[] } {
+ export function convertTypingOptionsFromJson(jsonOptions: any, basePath: string, configFileName?: string): { options: TypingOptions, errors: Diagnostic[] } {
const errors: Diagnostic[] = [];
const options = convertTypingOptionsFromJsonWorker(jsonOptions, basePath, errors, configFileName);
return { options, errors };
diff --git a/src/compiler/core.ts b/src/compiler/core.ts
index 8298a62f937..cab5c21ad90 100644
--- a/src/compiler/core.ts
+++ b/src/compiler/core.ts
@@ -1,5 +1,6 @@
-///
+///
///
+///
/* @internal */
@@ -47,6 +48,7 @@ namespace ts {
contains,
remove,
forEachValue: forEachValueInMap,
+ getKeys,
clear,
};
@@ -56,6 +58,14 @@ namespace ts {
}
}
+ function getKeys() {
+ const keys: Path[] = [];
+ for (const key in files) {
+ keys.push(key);
+ }
+ return keys;
+ }
+
// path should already be well-formed so it does not need to be normalized
function get(path: Path): T {
return files[toKey(path)];
@@ -311,18 +321,25 @@ namespace ts {
* @param array A sorted array whose first element must be no larger than number
* @param number The value to be searched for in the array.
*/
- export function binarySearch(array: number[], value: number): number {
+ export function binarySearch(array: T[], value: T, comparer?: (v1: T, v2: T) => number): number {
+ if (!array || array.length === 0) {
+ return -1;
+ }
+
let low = 0;
let high = array.length - 1;
+ comparer = comparer !== undefined
+ ? comparer
+ : (v1, v2) => (v1 < v2 ? -1 : (v1 > v2 ? 1 : 0));
while (low <= high) {
const middle = low + ((high - low) >> 1);
const midValue = array[middle];
- if (midValue === value) {
+ if (comparer(midValue, value) === 0) {
return middle;
}
- else if (midValue > value) {
+ else if (comparer(midValue, value) > 0) {
high = middle - 1;
}
else {
diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts
index 3642ee7f10a..648df9a702d 100644
--- a/src/compiler/declarationEmitter.ts
+++ b/src/compiler/declarationEmitter.ts
@@ -36,12 +36,12 @@ namespace ts {
return declarationDiagnostics.getDiagnostics(targetSourceFile ? targetSourceFile.fileName : undefined);
function getDeclarationDiagnosticsFromFile({ declarationFilePath }: EmitFileNames, sources: SourceFile[], isBundledEmit: boolean) {
- emitDeclarations(host, resolver, declarationDiagnostics, declarationFilePath, sources, isBundledEmit);
+ emitDeclarations(host, resolver, declarationDiagnostics, declarationFilePath, sources, isBundledEmit, /*emitOnlyDtsFiles*/ false);
}
}
function emitDeclarations(host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, declarationFilePath: string,
- sourceFiles: SourceFile[], isBundledEmit: boolean): DeclarationEmit {
+ sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean): DeclarationEmit {
const newLine = host.getNewLine();
const compilerOptions = host.getCompilerOptions();
@@ -98,7 +98,7 @@ namespace ts {
// global file reference is added only
// - if it is not bundled emit (because otherwise it would be self reference)
// - and it is not already added
- if (writeReferencePath(referencedFile, !isBundledEmit && !addedGlobalFileReference)) {
+ if (writeReferencePath(referencedFile, !isBundledEmit && !addedGlobalFileReference, emitOnlyDtsFiles)) {
addedGlobalFileReference = true;
}
emittedReferencedFiles.push(referencedFile);
@@ -1713,7 +1713,7 @@ namespace ts {
* @param referencedFile
* @param addBundledFileReference Determines if global file reference corresponding to bundled file should be emitted or not
*/
- function writeReferencePath(referencedFile: SourceFile, addBundledFileReference: boolean): boolean {
+ function writeReferencePath(referencedFile: SourceFile, addBundledFileReference: boolean, emitOnlyDtsFiles: boolean): boolean {
let declFileName: string;
let addedBundledEmitReference = false;
if (isDeclarationFile(referencedFile)) {
@@ -1722,7 +1722,7 @@ namespace ts {
}
else {
// Get the declaration file path
- forEachExpectedEmitFile(host, getDeclFileName, referencedFile);
+ forEachExpectedEmitFile(host, getDeclFileName, referencedFile, emitOnlyDtsFiles);
}
if (declFileName) {
@@ -1751,8 +1751,8 @@ namespace ts {
}
/* @internal */
- export function writeDeclarationFile(declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean, host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection) {
- const emitDeclarationResult = emitDeclarations(host, resolver, emitterDiagnostics, declarationFilePath, sourceFiles, isBundledEmit);
+ export function writeDeclarationFile(declarationFilePath: string, sourceFiles: SourceFile[], isBundledEmit: boolean, host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, emitOnlyDtsFiles: boolean) {
+ const emitDeclarationResult = emitDeclarations(host, resolver, emitterDiagnostics, declarationFilePath, sourceFiles, isBundledEmit, emitOnlyDtsFiles);
const emitSkipped = emitDeclarationResult.reportedDeclarationError || host.isEmitBlocked(declarationFilePath) || host.getCompilerOptions().noEmit;
if (!emitSkipped) {
const declarationOutput = emitDeclarationResult.referencesOutput
diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts
index 357a15507a4..c3fac679048 100644
--- a/src/compiler/emitter.ts
+++ b/src/compiler/emitter.ts
@@ -1,4 +1,4 @@
-///
+///
///
///
@@ -336,7 +336,7 @@ namespace ts {
}
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
- export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile): EmitResult {
+ export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile, emitOnlyDtsFiles?: boolean): EmitResult {
// emit output for the __extends helper function
const extendsHelper = `
var __extends = (this && this.__extends) || function (d, b) {
@@ -396,7 +396,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
const newLine = host.getNewLine();
const emitJavaScript = createFileEmitter();
- forEachExpectedEmitFile(host, emitFile, targetSourceFile);
+ forEachExpectedEmitFile(host, emitFile, targetSourceFile, emitOnlyDtsFiles);
return {
emitSkipped,
@@ -1615,7 +1615,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
else if (declaration.kind === SyntaxKind.ImportSpecifier) {
// Identifier references named import
write(getGeneratedNameForNode(declaration.parent.parent.parent));
- const name = (declaration).propertyName || (declaration).name;
+ const name = (declaration).propertyName || (declaration).name;
const identifier = getTextOfNodeFromSourceText(currentText, name);
if (languageVersion === ScriptTarget.ES3 && identifier === "default") {
write('["default"]');
@@ -3254,19 +3254,19 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
write("var ");
let seen: Map;
for (const id of convertedLoopState.hoistedLocalVariables) {
- // Don't initialize seen unless we have at least one element.
- // Emit a comma to separate for all but the first element.
- if (!seen) {
+ // Don't initialize seen unless we have at least one element.
+ // Emit a comma to separate for all but the first element.
+ if (!seen) {
seen = createMap();
- }
- else {
- write(", ");
- }
+ }
+ else {
+ write(", ");
+ }
if (!(id.text in seen)) {
- emit(id);
- seen[id.text] = id.text;
- }
+ emit(id);
+ seen[id.text] = id.text;
+ }
}
write(";");
writeLine();
@@ -7415,7 +7415,7 @@ const _super = (function (geti, seti) {
// - import equals declarations that import external modules are not emitted
continue;
}
- // fall-though for import declarations that import internal modules
+ // fall-though for import declarations that import internal modules
default:
writeLine();
emit(statement);
@@ -8364,24 +8364,28 @@ const _super = (function (geti, seti) {
}
}
- function emitFile({ jsFilePath, sourceMapFilePath, declarationFilePath}: { jsFilePath: string, sourceMapFilePath: string, declarationFilePath: string },
- sourceFiles: SourceFile[], isBundledEmit: boolean) {
- // Make sure not to write js File and source map file if any of them cannot be written
- if (!host.isEmitBlocked(jsFilePath) && !compilerOptions.noEmit) {
- emitJavaScript(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit);
- }
- else {
- emitSkipped = true;
+ function emitFile({ jsFilePath, sourceMapFilePath, declarationFilePath }: EmitFileNames,
+ sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean) {
+ if (!emitOnlyDtsFiles) {
+ // Make sure not to write js File and source map file if any of them cannot be written
+ if (!host.isEmitBlocked(jsFilePath) && !compilerOptions.noEmit) {
+ emitJavaScript(jsFilePath, sourceMapFilePath, sourceFiles, isBundledEmit);
+ }
+ else {
+ emitSkipped = true;
+ }
}
if (declarationFilePath) {
- emitSkipped = writeDeclarationFile(declarationFilePath, sourceFiles, isBundledEmit, host, resolver, emitterDiagnostics) || emitSkipped;
+ emitSkipped = writeDeclarationFile(declarationFilePath, sourceFiles, isBundledEmit, host, resolver, emitterDiagnostics, emitOnlyDtsFiles) || emitSkipped;
}
if (!emitSkipped && emittedFilesList) {
- emittedFilesList.push(jsFilePath);
- if (sourceMapFilePath) {
- emittedFilesList.push(sourceMapFilePath);
+ if (!emitOnlyDtsFiles) {
+ emittedFilesList.push(jsFilePath);
+ if (sourceMapFilePath) {
+ emittedFilesList.push(sourceMapFilePath);
+ }
}
if (declarationFilePath) {
emittedFilesList.push(declarationFilePath);
diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts
index 4f63448ecd2..3e20f899c2d 100644
--- a/src/compiler/parser.ts
+++ b/src/compiler/parser.ts
@@ -1,4 +1,4 @@
-///
+///
///
namespace ts {
diff --git a/src/compiler/program.ts b/src/compiler/program.ts
index 9deb9674279..932f400660f 100644
--- a/src/compiler/program.ts
+++ b/src/compiler/program.ts
@@ -774,15 +774,15 @@ namespace ts {
return noDiagnosticsTypeChecker || (noDiagnosticsTypeChecker = createTypeChecker(program, /*produceDiagnostics:*/ false));
}
- function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult {
- return runWithCancellationToken(() => emitWorker(program, sourceFile, writeFileCallback, cancellationToken));
+ function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean): EmitResult {
+ return runWithCancellationToken(() => emitWorker(program, sourceFile, writeFileCallback, cancellationToken, emitOnlyDtsFiles));
}
function isEmitBlocked(emitFileName: string): boolean {
return hasEmitBlockingDiagnostics.contains(toPath(emitFileName, currentDirectory, getCanonicalFileName));
}
- function emitWorker(program: Program, sourceFile: SourceFile, writeFileCallback: WriteFileCallback, cancellationToken: CancellationToken): EmitResult {
+ function emitWorker(program: Program, sourceFile: SourceFile, writeFileCallback: WriteFileCallback, cancellationToken: CancellationToken, emitOnlyDtsFiles?: boolean): EmitResult {
let declarationDiagnostics: Diagnostic[] = [];
if (options.noEmit) {
@@ -827,7 +827,8 @@ namespace ts {
const emitResult = emitFiles(
emitResolver,
getEmitHost(writeFileCallback),
- sourceFile);
+ sourceFile,
+ emitOnlyDtsFiles);
performance.mark("afterEmit");
performance.measure("Emit", "beforeEmit", "afterEmit");
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index 974f2a1d82b..202f45eb153 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -19,6 +19,7 @@ namespace ts {
remove(fileName: Path): void;
forEachValue(f: (key: Path, v: T) => void): void;
+ getKeys(): Path[];
clear(): void;
}
@@ -1755,7 +1756,7 @@ namespace ts {
* used for writing the JavaScript and declaration files. Otherwise, the writeFile parameter
* will be invoked when writing the JavaScript and declaration files.
*/
- emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult;
+ emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean): EmitResult;
getOptionsDiagnostics(cancellationToken?: CancellationToken): Diagnostic[];
getGlobalDiagnostics(cancellationToken?: CancellationToken): Diagnostic[];
@@ -2736,6 +2737,7 @@ namespace ts {
raw?: any;
errors: Diagnostic[];
wildcardDirectories?: MapLike;
+ compileOnSave?: boolean;
}
export const enum WatchDirectoryFlags {
diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts
index f0351a39bb5..b4e4418dac2 100644
--- a/src/compiler/utilities.ts
+++ b/src/compiler/utilities.ts
@@ -1,4 +1,4 @@
-///
+///
/* @internal */
namespace ts {
@@ -2218,12 +2218,10 @@ namespace ts {
const options = host.getCompilerOptions();
const outputDir = options.declarationDir || options.outDir; // Prefer declaration folder if specified
- if (options.declaration) {
- const path = outputDir
- ? getSourceFilePathInNewDir(sourceFile, host, outputDir)
- : sourceFile.fileName;
- return removeFileExtension(path) + ".d.ts";
- }
+ const path = outputDir
+ ? getSourceFilePathInNewDir(sourceFile, host, outputDir)
+ : sourceFile.fileName;
+ return removeFileExtension(path) + ".d.ts";
}
export interface EmitFileNames {
@@ -2233,8 +2231,9 @@ namespace ts {
}
export function forEachExpectedEmitFile(host: EmitHost,
- action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean) => void,
- targetSourceFile?: SourceFile) {
+ action: (emitFileNames: EmitFileNames, sourceFiles: SourceFile[], isBundledEmit: boolean, emitOnlyDtsFiles: boolean) => void,
+ targetSourceFile?: SourceFile,
+ emitOnlyDtsFiles?: boolean) {
const options = host.getCompilerOptions();
// Emit on each source file
if (options.outFile || options.out) {
@@ -2267,12 +2266,13 @@ namespace ts {
}
}
const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, extension);
+ const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (emitOnlyDtsFiles || options.declaration) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
const emitFileNames: EmitFileNames = {
jsFilePath,
sourceMapFilePath: getSourceMapFilePath(jsFilePath, options),
- declarationFilePath: !isSourceFileJavaScript(sourceFile) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined
+ declarationFilePath
};
- action(emitFileNames, [sourceFile], /*isBundledEmit*/false);
+ action(emitFileNames, [sourceFile], /*isBundledEmit*/false, emitOnlyDtsFiles);
}
function onBundledEmit(host: EmitHost) {
@@ -2290,7 +2290,7 @@ namespace ts {
sourceMapFilePath: getSourceMapFilePath(jsFilePath, options),
declarationFilePath: options.declaration ? removeFileExtension(jsFilePath) + ".d.ts" : undefined
};
- action(emitFileNames, bundledSources, /*isBundledEmit*/true);
+ action(emitFileNames, bundledSources, /*isBundledEmit*/true, emitOnlyDtsFiles);
}
}
diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts
index 5da61fd542a..a210349c146 100644
--- a/src/harness/harnessLanguageService.ts
+++ b/src/harness/harnessLanguageService.ts
@@ -698,7 +698,8 @@ namespace Harness.LanguageService {
/*useOneInferredProject*/ false,
/*typingsInstaller*/ undefined,
Utils.byteLength,
- process.hrtime, serverHost);
+ process.hrtime, serverHost,
+ /*canUseEvents*/ true);
// Fake the connection between the client and the server
serverHost.writeMessage = client.onMessage.bind(client);
diff --git a/src/harness/unittests/session.ts b/src/harness/unittests/session.ts
index 0d1fb3681e0..abfac4b082d 100644
--- a/src/harness/unittests/session.ts
+++ b/src/harness/unittests/session.ts
@@ -44,7 +44,7 @@ namespace ts.server {
let lastSent: protocol.Message;
beforeEach(() => {
- session = new Session(mockHost, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined, Utils.byteLength, process.hrtime, mockLogger);
+ session = new Session(mockHost, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined, Utils.byteLength, process.hrtime, mockLogger, /*canUseEvents*/ true);
session.send = (msg: protocol.Message) => {
lastSent = msg;
};
@@ -269,7 +269,7 @@ namespace ts.server {
lastSent: protocol.Message;
customHandler = "testhandler";
constructor() {
- super(mockHost, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined, Utils.byteLength, process.hrtime, mockLogger);
+ super(mockHost, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined, Utils.byteLength, process.hrtime, mockLogger, /*canUseEvents*/ true);
this.addProtocolHandler(this.customHandler, () => {
return { response: undefined, responseRequired: true };
});
@@ -327,7 +327,7 @@ namespace ts.server {
class InProcSession extends Session {
private queue: protocol.Request[] = [];
constructor(private client: InProcClient) {
- super(mockHost, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined, Utils.byteLength, process.hrtime, mockLogger);
+ super(mockHost, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined, Utils.byteLength, process.hrtime, mockLogger, /*canUseEvents*/ true);
this.addProtocolHandler("echo", (req: protocol.Request) => ({
response: req.arguments,
responseRequired: true
diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts
index 2a309057dbe..813ea189157 100644
--- a/src/harness/unittests/tsserverProjectSystem.ts
+++ b/src/harness/unittests/tsserverProjectSystem.ts
@@ -1,4 +1,4 @@
-///
+///
///
namespace ts {
@@ -36,7 +36,7 @@ namespace ts {
}
safeFileList = "";
- postInstallActions: (( map: (t: string[]) => string[]) => void)[] = [];
+ postInstallActions: ((map: (t: string[]) => string[]) => void)[] = [];
runPostInstallActions(map: (t: string[]) => string[]) {
for (const f of this.postInstallActions) {
@@ -46,7 +46,6 @@ namespace ts {
}
onProjectClosed(p: server.Project) {
-
}
attach(projectService: server.ProjectService) {
@@ -114,6 +113,32 @@ namespace ts {
fileOrFolderList);
}
+ interface CreateProjectServiceParameters {
+ cancellationToken?: HostCancellationToken;
+ logger?: server.Logger;
+ useSingleInferredProject?: boolean;
+ typingsInstaller?: server.ITypingsInstaller;
+ eventHandler?: server.ProjectServiceEventHandler;
+ }
+
+
+ class TestProjectService extends server.ProjectService {
+ constructor(host: server.ServerHost, logger: server.Logger, cancellationToken: HostCancellationToken, useSingleInferredProject: boolean,
+ typingsInstaller: server.ITypingsInstaller, eventHandler: server.ProjectServiceEventHandler) {
+ super(host, logger, cancellationToken, useSingleInferredProject, typingsInstaller, eventHandler);
+ }
+
+ checkNumberOfProjects(count: { inferredProjects?: number, configuredProjects?: number, externalProjects?: number }) {
+ checkNumberOfProjects(this, count);
+ }
+ }
+ function createProjectService(host: server.ServerHost, parameters: CreateProjectServiceParameters = {}) {
+ const cancellationToken = parameters.cancellationToken || nullCancellationToken;
+ const logger = parameters.logger || nullLogger;
+ const useSingleInferredProject = parameters.useSingleInferredProject !== undefined ? parameters.useSingleInferredProject : false;
+ return new TestProjectService(host, logger, cancellationToken, useSingleInferredProject, parameters.typingsInstaller, parameters.eventHandler);
+ }
+
interface FileOrFolder {
path: string;
content?: string;
@@ -256,7 +281,7 @@ namespace ts {
private timeoutCallbacks = new Callbacks();
private immediateCallbacks = new Callbacks();
- readonly watchedDirectories = createMap<{ cb: DirectoryWatcherCallback, recursive: boolean }[]>();
+ readonly watchedDirectories = createMap<{ cb: DirectoryWatcherCallback, recursive: boolean }[]>();
readonly watchedFiles = createMap();
private filesOrFolders: FileOrFolder[];
@@ -415,7 +440,7 @@ namespace ts {
setImmediate(callback: TimeOutCallback, time: number, ...args: any[]) {
return this.immediateCallbacks.register(callback, args);
- };
+ }
clearImmediate(timeoutId: any): void {
this.immediateCallbacks.unregister(timeoutId);
@@ -454,6 +479,23 @@ namespace ts {
readonly exit = () => notImplemented();
}
+ function makeSessionRequest(command: string, args: T) {
+ const newRequest: server.protocol.Request = {
+ seq: 0,
+ type: "request",
+ command,
+ arguments: args
+ };
+ return newRequest;
+ }
+
+ function openFilesForSession(files: FileOrFolder[], session: server.Session) {
+ for (const file of files) {
+ const request = makeSessionRequest(server.CommandNames.Open, { file: file.path });
+ session.executeCommand(request);
+ }
+ }
+
describe("tsserver-project-system", () => {
const commonFile1: FileOrFolder = {
path: "/a/b/commonFile1.ts",
@@ -478,7 +520,7 @@ namespace ts {
content: `export let x: number`
};
const host = createServerHost([appFile, moduleFile, libFile]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
const { configFileName } = projectService.openClientFile(appFile.path);
assert(!configFileName, `should not find config, got: '${configFileName}`);
@@ -516,7 +558,7 @@ namespace ts {
};
const host = createServerHost([configFile, libFile, file1, file2, file3]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
const { configFileName, configFileErrors } = projectService.openClientFile(file1.path);
assert(configFileName, "should find config file");
@@ -543,7 +585,7 @@ namespace ts {
const host = createServerHost(filesWithoutConfig);
const filesWithConfig = [libFile, commonFile1, commonFile2, configFile];
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(commonFile1.path);
projectService.openClientFile(commonFile2.path);
@@ -574,7 +616,7 @@ namespace ts {
content: `{}`
};
const host = createServerHost([commonFile1, libFile, configFile]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(commonFile1.path);
checkWatchedDirectories(host, ["/a/b"]);
checkNumberOfConfiguredProjects(projectService, 1);
@@ -602,7 +644,7 @@ namespace ts {
}`
};
const host = createServerHost([commonFile1, commonFile2, configFile]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(commonFile1.path);
projectService.openClientFile(commonFile2.path);
@@ -618,7 +660,7 @@ namespace ts {
content: `{}`
};
const host = createServerHost([commonFile1, commonFile2, configFile]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(commonFile1.path);
checkNumberOfConfiguredProjects(projectService, 1);
@@ -648,7 +690,7 @@ namespace ts {
};
const files = [commonFile1, commonFile2, configFile];
const host = createServerHost(files);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(commonFile1.path);
const project = projectService.configuredProjects[0];
@@ -681,7 +723,7 @@ namespace ts {
};
const host = createServerHost([commonFile1, commonFile2, excludedFile1, configFile]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(commonFile1.path);
checkNumberOfConfiguredProjects(projectService, 1);
@@ -715,7 +757,7 @@ namespace ts {
};
const files = [file1, nodeModuleFile, classicModuleFile, configFile];
const host = createServerHost(files);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
projectService.openClientFile(nodeModuleFile.path);
projectService.openClientFile(classicModuleFile.path);
@@ -756,7 +798,7 @@ namespace ts {
}`
};
const host = createServerHost([file1, file2, configFile]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
projectService.closeClientFile(file1.path);
projectService.openClientFile(file2.path);
@@ -783,7 +825,7 @@ namespace ts {
}`
};
const host = createServerHost([file1, file2, configFile]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
projectService.closeClientFile(file1.path);
projectService.openClientFile(file2.path);
@@ -801,7 +843,7 @@ namespace ts {
content: `{
"compilerOptions": {
"target": "es6"
- },
+ },
"files": [ "main.ts" ]
}`
};
@@ -816,7 +858,7 @@ namespace ts {
};
const host = createServerHost([file1, file2, file3, libFile]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ true, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host, { useSingleInferredProject: true });
projectService.openClientFile(file1.path);
projectService.openClientFile(file2.path);
projectService.openClientFile(file3.path);
@@ -844,12 +886,12 @@ namespace ts {
content: `{
"compilerOptions": {
"target": "es6"
- },
+ },
"files": [ "main.ts" ]
}`
};
const host = createServerHost([file1, configFile, libFile]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ true, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host, { useSingleInferredProject: true });
projectService.openClientFile(file1.path);
checkNumberOfConfiguredProjects(projectService, 1);
@@ -868,7 +910,7 @@ namespace ts {
};
const externalProjectName = "externalproject";
const host = createServerHost([file1, file2]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openExternalProject({
rootFiles: toExternalFiles([file1.path, file2.path]),
options: {},
@@ -926,7 +968,7 @@ namespace ts {
};
const externalProjectName = "externalproject";
const host = createServerHost([file1, file2, file3, config1, config2]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openExternalProject({
rootFiles: toExternalFiles([config1.path, config2.path, file3.path]),
options: {},
@@ -964,7 +1006,7 @@ namespace ts {
};
const externalProjectName = "externalproject";
const host = createServerHost([file1, configFile]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
@@ -995,7 +1037,7 @@ namespace ts {
};
const externalProjectName = "externalproject";
const host = createServerHost([file1, configFile]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
@@ -1030,7 +1072,7 @@ namespace ts {
content: `export let y = 1;`
};
const host = createServerHost([file1, file2, file3]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useSingleInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
@@ -1067,7 +1109,7 @@ namespace ts {
content: `export let y = 1;`
};
const host = createServerHost([file1, file2, file3]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useSingleInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
@@ -1106,7 +1148,7 @@ namespace ts {
};
const host = createServerHost([file1, file2, file3]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useSingleInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
checkNumberOfProjects(projectService, { inferredProjects: 1 });
@@ -1139,7 +1181,7 @@ namespace ts {
content: "export let y = 1;"
};
const host = createServerHost([file1, file2, file3]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useSingleInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(file2.path);
checkNumberOfProjects(projectService, { inferredProjects: 1 });
@@ -1174,7 +1216,7 @@ namespace ts {
};
const host = createServerHost([file1, configFile]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useSingleInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
@@ -1205,7 +1247,7 @@ namespace ts {
};
const host = createServerHost([file1, file2, configFile]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useSingleInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
@@ -1238,7 +1280,7 @@ namespace ts {
};
const host = createServerHost([file1, file2, configFile]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useSingleInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
@@ -1266,7 +1308,7 @@ namespace ts {
content: "let y = 1"
};
const host = createServerHost([file1, file2]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useSingleInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles([file1.path]) });
checkNumberOfProjects(projectService, { externalProjects: 1 });
@@ -1292,7 +1334,7 @@ namespace ts {
};
const host = createServerHost([file1, file2, file3]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useSingleInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openExternalProject({ projectFileName: "project", options: { moduleResolution: ModuleResolutionKind.NodeJs }, rootFiles: toExternalFiles([file1.path, file2.path]) });
checkNumberOfProjects(projectService, { externalProjects: 1 });
@@ -1319,7 +1361,7 @@ namespace ts {
content: JSON.stringify({ compilerOptions: {} })
};
const host = createServerHost([file1, file2, config]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useSingleInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
checkNumberOfProjects(projectService, { configuredProjects: 1 });
@@ -1347,7 +1389,7 @@ namespace ts {
content: "export let x = 1"
};
const host = createServerHost([file1, file2]);
- const projectService = new server.ProjectService(host, nullLogger, nullCancellationToken, /*useSingleInferredProject*/ false, /*typingsInstaller*/ undefined);
+ const projectService = createProjectService(host);
projectService.openClientFile(file1.path);
projectService.openClientFile(file2.path);
@@ -1372,7 +1414,7 @@ namespace ts {
content: `