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: `