diff --git a/scripts/buildProtocol.ts b/scripts/buildProtocol.ts index 55ad086815c68..66f29f577d933 100644 --- a/scripts/buildProtocol.ts +++ b/scripts/buildProtocol.ts @@ -10,6 +10,8 @@ function endsWith(s: string, suffix: string) { class DeclarationsWalker { private visitedTypes: ts.Type[] = []; private text = ""; + private removedTypes: ts.Type[] = []; + private constructor(private typeChecker: ts.TypeChecker, private protocolFile: ts.SourceFile) { } @@ -17,9 +19,18 @@ class DeclarationsWalker { let text = "declare namespace ts.server.protocol {\n"; var walker = new DeclarationsWalker(typeChecker, protocolFile); walker.visitTypeNodes(protocolFile); - return walker.text + text = walker.text ? `declare namespace ts.server.protocol {\n${walker.text}}` : ""; + if (walker.removedTypes) { + text += "\ndeclare namespace ts {\n"; + text += " // these types are empty stubs for types from services and should not be used directly\n" + for (const type of walker.removedTypes) { + text += ` export type ${type.symbol.name} = never;\n`; + } + text += "}" + } + return text; } private processType(type: ts.Type): void { @@ -41,19 +52,18 @@ class DeclarationsWalker { if (sourceFile === this.protocolFile || path.basename(sourceFile.fileName) === "lib.d.ts") { return; } - // splice declaration in final d.ts file - let text = decl.getFullText(); - if (decl.kind === ts.SyntaxKind.EnumDeclaration && !(decl.flags & ts.NodeFlags.Const)) { - // patch enum declaration to make them constan - const declStart = decl.getStart() - decl.getFullStart(); - const prefix = text.substring(0, declStart); - const suffix = text.substring(declStart + "enum".length, decl.getEnd() - decl.getFullStart()); - text = prefix + "const enum" + suffix; + if (decl.kind === ts.SyntaxKind.EnumDeclaration) { + this.removedTypes.push(type); + return; } - this.text += `${text}\n`; + else { + // splice declaration in final d.ts file + let text = decl.getFullText(); + this.text += `${text}\n`; + // recursively pull all dependencies into result dts file - // recursively pull all dependencies into result dts file - this.visitTypeNodes(decl); + this.visitTypeNodes(decl); + } } } } @@ -69,15 +79,37 @@ class DeclarationsWalker { case ts.SyntaxKind.Parameter: case ts.SyntaxKind.IndexSignature: if (((node.parent).type) === node) { - const type = this.typeChecker.getTypeAtLocation(node); - if (type && !(type.flags & ts.TypeFlags.TypeParameter)) { - this.processType(type); - } + this.processTypeOfNode(node); } break; + case ts.SyntaxKind.InterfaceDeclaration: + const heritageClauses = (node.parent).heritageClauses; + if (heritageClauses) { + if (heritageClauses[0].token !== ts.SyntaxKind.ExtendsKeyword) { + throw new Error(`Unexpected kind of heritage clause: ${ts.SyntaxKind[heritageClauses[0].kind]}`); + } + for (const type of heritageClauses[0].types) { + this.processTypeOfNode(type); + } + } + break; } } ts.forEachChild(node, n => this.visitTypeNodes(n)); + } + + private processTypeOfNode(node: ts.Node): void { + if (node.kind === ts.SyntaxKind.UnionType) { + for (const t of (node).types) { + this.processTypeOfNode(t); + } + } + else { + const type = this.typeChecker.getTypeAtLocation(node); + if (type && !(type.flags & (ts.TypeFlags.TypeParameter))) { + this.processType(type); + } + } } } @@ -128,9 +160,12 @@ function generateProtocolFile(protocolTs: string, typeScriptServicesDts: string) if (extraDeclarations) { protocolDts += extraDeclarations; } + protocolDts += "\nimport protocol = ts.server.protocol;"; + protocolDts += "\nexport = protocol;"; + protocolDts += "\nexport as namespace protocol;"; // do sanity check and try to compile generated text as standalone program const sanityCheckProgram = getProgramWithProtocolText(protocolDts, /*includeTypeScriptServices*/ false); - const diagnostics = [...program.getSyntacticDiagnostics(), ...program.getSemanticDiagnostics(), ...program.getGlobalDiagnostics()]; + const diagnostics = [...sanityCheckProgram.getSyntacticDiagnostics(), ...sanityCheckProgram.getSemanticDiagnostics(), ...sanityCheckProgram.getGlobalDiagnostics()]; if (diagnostics.length) { const flattenedDiagnostics = diagnostics.map(d => ts.flattenDiagnosticMessageText(d.messageText, "\n")).join("\n"); throw new Error(`Unexpected errors during sanity check: ${flattenedDiagnostics}`); diff --git a/src/harness/unittests/session.ts b/src/harness/unittests/session.ts index badbbaf526b7a..9099f0a4285d1 100644 --- a/src/harness/unittests/session.ts +++ b/src/harness/unittests/session.ts @@ -39,12 +39,18 @@ namespace ts.server { getLogFileName: (): string => undefined }; + class TestSession extends Session { + getProjectService() { + return this.projectService; + } + } + describe("the Session class", () => { - let session: Session; + let session: TestSession; let lastSent: protocol.Message; beforeEach(() => { - session = new Session(mockHost, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined, Utils.byteLength, process.hrtime, mockLogger, /*canUseEvents*/ true); + session = new TestSession(mockHost, nullCancellationToken, /*useOneInferredProject*/ false, /*typingsInstaller*/ undefined, Utils.byteLength, process.hrtime, mockLogger, /*canUseEvents*/ true); session.send = (msg: protocol.Message) => { lastSent = msg; }; @@ -55,7 +61,7 @@ namespace ts.server { const req: protocol.FileRequest = { command: CommandNames.Open, seq: 0, - type: "command", + type: "request", arguments: { file: undefined } @@ -67,7 +73,7 @@ namespace ts.server { const req: protocol.Request = { command: "foobar", seq: 0, - type: "command" + type: "request" }; session.executeCommand(req); @@ -85,7 +91,7 @@ namespace ts.server { const req: protocol.ConfigureRequest = { command: CommandNames.Configure, seq: 0, - type: "command", + type: "request", arguments: { hostInfo: "unit test", formatOptions: { @@ -106,6 +112,47 @@ namespace ts.server { body: undefined }); }); + it ("should handle literal types in request", () => { + const configureRequest: protocol.ConfigureRequest = { + command: CommandNames.Configure, + seq: 0, + type: "request", + arguments: { + formatOptions: { + indentStyle: "Block" + } + } + }; + + session.onMessage(JSON.stringify(configureRequest)); + + assert.equal(session.getProjectService().getFormatCodeOptions().indentStyle, IndentStyle.Block); + + const setOptionsRequest: protocol.SetCompilerOptionsForInferredProjectsRequest = { + command: CommandNames.CompilerOptionsForInferredProjects, + seq: 1, + type: "request", + arguments: { + options: { + module: "System", + target: "ES5", + jsx: "React", + newLine: "Lf", + moduleResolution: "Node" + } + } + }; + session.onMessage(JSON.stringify(setOptionsRequest)); + assert.deepEqual( + session.getProjectService().getCompilerOptionsForInferredProjects(), + { + module: ModuleKind.System, + target: ScriptTarget.ES5, + jsx: JsxEmit.React, + newLine: NewLineKind.LineFeed, + moduleResolution: ModuleResolutionKind.NodeJs + }); + }); }); describe("onMessage", () => { @@ -118,7 +165,7 @@ namespace ts.server { const req: protocol.Request = { command: name, seq: i, - type: "command" + type: "request" }; i++; session.onMessage(JSON.stringify(req)); @@ -151,7 +198,7 @@ namespace ts.server { const req: protocol.ConfigureRequest = { command: CommandNames.Configure, seq: 0, - type: "command", + type: "request", arguments: { hostInfo: "unit test", formatOptions: { @@ -175,7 +222,7 @@ namespace ts.server { describe("send", () => { it("is an overrideable handle which sends protocol messages over the wire", () => { - const msg = { seq: 0, type: "none" }; + const msg: server.protocol.Request = { seq: 0, type: "request", command: "" }; const strmsg = JSON.stringify(msg); const len = 1 + Utils.byteLength(strmsg, "utf8"); const resultMsg = `Content-Length: ${len}\r\n\r\n${strmsg}\n`; @@ -203,7 +250,7 @@ namespace ts.server { expect(session.executeCommand({ command, seq: 0, - type: "command" + type: "request" })).to.deep.equal(result); }); it("throws when a duplicate handler is passed", () => { @@ -304,7 +351,7 @@ namespace ts.server { expect(session.executeCommand({ seq: 0, - type: "command", + type: "request", command: session.customHandler })).to.deep.equal({ response: undefined, @@ -405,7 +452,7 @@ namespace ts.server { this.seq++; this.server.enqueue({ seq: this.seq, - type: "command", + type: "request", command, arguments: args }); diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 54b257242fdeb..6556aa0146046 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -17,6 +17,68 @@ namespace ts.server { (event: ProjectServiceEvent): void; } + function prepareConvertersForEnumLikeCompilerOptions(commandLineOptions: CommandLineOption[]): Map> { + const map: Map> = createMap>(); + for (const option of commandLineOptions) { + if (typeof option.type === "object") { + const optionMap = >option.type; + // verify that map contains only numbers + for (const id in optionMap) { + Debug.assert(typeof optionMap[id] === "number"); + } + map[option.name] = optionMap; + } + } + return map; + } + + const compilerOptionConverters = prepareConvertersForEnumLikeCompilerOptions(optionDeclarations); + const indentStyle = createMap({ + "none": IndentStyle.None, + "block": IndentStyle.Block, + "smart": IndentStyle.Smart + }); + + export function convertFormatOptions(protocolOptions: protocol.FormatCodeSettings): FormatCodeSettings { + if (typeof protocolOptions.indentStyle === "string") { + protocolOptions.indentStyle = indentStyle[protocolOptions.indentStyle.toLowerCase()]; + Debug.assert(protocolOptions.indentStyle !== undefined); + } + return protocolOptions; + } + + export function convertCompilerOptions(protocolOptions: protocol.ExternalProjectCompilerOptions): CompilerOptions & protocol.CompileOnSaveMixin { + for (const id in compilerOptionConverters) { + const propertyValue = protocolOptions[id]; + if (typeof propertyValue === "string") { + const mappedValues = compilerOptionConverters[id]; + protocolOptions[id] = mappedValues[propertyValue.toLowerCase()]; + } + } + return protocolOptions; + } + + export function tryConvertScriptKindName(scriptKindName: protocol.ScriptKindName | ScriptKind): ScriptKind { + return typeof scriptKindName === "string" + ? convertScriptKindName(scriptKindName) + : scriptKindName; + } + + export function convertScriptKindName(scriptKindName: protocol.ScriptKindName) { + switch (scriptKindName) { + case "JS": + return ScriptKind.JS; + case "JSX": + return ScriptKind.JSX; + case "TS": + return ScriptKind.TS; + case "TSX": + return ScriptKind.TSX; + default: + return ScriptKind.Unknown; + } + } + /** * This helper function processes a list of projects and return the concatenated, sortd and deduplicated output of processing each project. */ @@ -63,7 +125,7 @@ namespace ts.server { const externalFilePropertyReader: FilePropertyReader = { getFileName: x => x.fileName, - getScriptKind: x => x.scriptKind, + getScriptKind: x => tryConvertScriptKindName(x.scriptKind), hasMixedContent: x => x.hasMixedContent }; @@ -214,6 +276,10 @@ namespace ts.server { this.ensureInferredProjectsUpToDate(); } + getCompilerOptionsForInferredProjects() { + return this.compilerOptionsForInferredProjects; + } + updateTypingsForProject(response: SetTypings | InvalidateCachedTypings): void { const project = this.findProject(response.projectName); if (!project) { @@ -231,10 +297,10 @@ namespace ts.server { } setCompilerOptionsForInferredProjects(projectCompilerOptions: protocol.ExternalProjectCompilerOptions): void { - this.compilerOptionsForInferredProjects = projectCompilerOptions; + this.compilerOptionsForInferredProjects = convertCompilerOptions(projectCompilerOptions); this.compileOnSaveForInferredProjects = projectCompilerOptions.compileOnSave; for (const proj of this.inferredProjects) { - proj.setCompilerOptions(projectCompilerOptions); + proj.setCompilerOptions(this.compilerOptionsForInferredProjects); proj.compileOnSaveEnabled = projectCompilerOptions.compileOnSave; } this.updateProjectGraphs(this.inferredProjects); @@ -744,12 +810,13 @@ namespace ts.server { } private createAndAddExternalProject(projectFileName: string, files: protocol.ExternalFile[], options: protocol.ExternalProjectCompilerOptions, typingOptions: TypingOptions) { + const compilerOptions = convertCompilerOptions(options); const project = new ExternalProject( projectFileName, this, this.documentRegistry, - options, - /*languageServiceEnabled*/ !this.exceededTotalSizeLimitForNonTsFiles(options, files, externalFilePropertyReader), + compilerOptions, + /*languageServiceEnabled*/ !this.exceededTotalSizeLimitForNonTsFiles(compilerOptions, files, externalFilePropertyReader), options.compileOnSave === undefined ? true : options.compileOnSave); this.addFilesToProjectAndUpdateGraph(project, files, externalFilePropertyReader, /*clientFileName*/ undefined, typingOptions, /*configFileErrors*/ undefined); @@ -1018,7 +1085,7 @@ namespace ts.server { if (args.file) { const info = this.getScriptInfoForNormalizedPath(toNormalizedPath(args.file)); if (info) { - info.setFormatOptions(args.formatOptions); + info.setFormatOptions(convertFormatOptions(args.formatOptions)); this.logger.info(`Host configuration update for file ${args.file}`); } } @@ -1028,7 +1095,7 @@ namespace ts.server { this.logger.info(`Host information ${args.hostInfo}`); } if (args.formatOptions) { - mergeMaps(this.hostConfiguration.formatCodeOptions, args.formatOptions); + mergeMaps(this.hostConfiguration.formatCodeOptions, convertFormatOptions(args.formatOptions)); this.logger.info("Format host information updated"); } } @@ -1142,7 +1209,7 @@ namespace ts.server { const scriptInfo = this.getScriptInfo(file.fileName); Debug.assert(!scriptInfo || !scriptInfo.isOpen); const normalizedPath = scriptInfo ? scriptInfo.fileName : toNormalizedPath(file.fileName); - this.openClientFileWithNormalizedPath(normalizedPath, file.content, file.scriptKind, file.hasMixedContent); + this.openClientFileWithNormalizedPath(normalizedPath, file.content, tryConvertScriptKindName(file.scriptKind), file.hasMixedContent); } } @@ -1235,7 +1302,7 @@ namespace ts.server { if (externalProject) { if (!tsConfigFiles) { // external project already exists and not config files were added - update the project and return; - this.updateNonInferredProject(externalProject, proj.rootFiles, externalFilePropertyReader, proj.options, proj.typingOptions, proj.options.compileOnSave, /*configFileErrors*/ undefined); + this.updateNonInferredProject(externalProject, proj.rootFiles, externalFilePropertyReader, convertCompilerOptions(proj.options), proj.typingOptions, proj.options.compileOnSave, /*configFileErrors*/ undefined); return; } // some config files were added to external project (that previously were not there) diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 80623f05aec3a..7da95e49575f5 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -109,7 +109,7 @@ namespace ts.server.protocol { /** * One of "request", "response", or "event" */ - type: string; + type: "request" | "response" | "event"; } /** @@ -833,7 +833,7 @@ namespace ts.server.protocol { /** * Script kind of the file */ - scriptKind?: ScriptKind; + scriptKind?: ScriptKindName | ts.ScriptKind; /** * Whether file has mixed content (i.e. .cshtml file that combines html markup with C#/JavaScript) */ @@ -866,20 +866,23 @@ namespace ts.server.protocol { typingOptions?: TypingOptions; } - /** - * For external projects, some of the project settings are sent together with - * compiler settings. - */ - export interface ExternalProjectCompilerOptions extends CompilerOptions { + export interface CompileOnSaveMixin { /** * If compile on save is enabled for the project */ compileOnSave?: boolean; } + /** + * For external projects, some of the project settings are sent together with + * compiler settings. + */ + export type ExternalProjectCompilerOptions = CompilerOptions & CompileOnSaveMixin; + /** * Contains information about current project version */ + /* @internal */ export interface ProjectVersionInfo { /** * Project name @@ -896,7 +899,7 @@ namespace ts.server.protocol { /** * Current set of compiler options for project */ - options: CompilerOptions; + options: ts.CompilerOptions; } /** @@ -920,6 +923,7 @@ namespace ts.server.protocol { * if changes is set - then this is the set of changes that should be applied to existing project * otherwise - assume that nothing is changed */ + /* @internal */ export interface ProjectFiles { /** * Information abount project verison @@ -938,6 +942,7 @@ namespace ts.server.protocol { /** * Combines project information with project level errors. */ + /* @internal */ export interface ProjectFilesWithDiagnostics extends ProjectFiles { /** * List of errors in project @@ -1012,9 +1017,11 @@ namespace ts.server.protocol { * Used to specify the script kind of the file explicitly. It could be one of the following: * "TS", "JS", "TSX", "JSX" */ - scriptKindName?: "TS" | "JS" | "TSX" | "JSX"; + scriptKindName?: ScriptKindName; } + export type ScriptKindName = "TS" | "JS" | "TSX" | "JSX"; + /** * Open request; value of command field is "open". Notify the * server that the client has file open. The server will not @@ -1109,6 +1116,7 @@ namespace ts.server.protocol { /** * Arguments to SynchronizeProjectListRequest */ + /* @internal */ export interface SynchronizeProjectListRequestArgs { /** * List of last known projects @@ -2056,4 +2064,141 @@ namespace ts.server.protocol { export interface NavTreeResponse extends Response { body?: NavigationTree; } + + export namespace IndentStyle { + export type None = "None"; + export type Block = "Block"; + export type Smart = "Smart"; + } + + export type IndentStyle = IndentStyle.None | IndentStyle.Block | IndentStyle.Smart; + + export interface EditorSettings { + baseIndentSize?: number; + indentSize?: number; + tabSize?: number; + newLineCharacter?: string; + convertTabsToSpaces?: boolean; + indentStyle?: IndentStyle | ts.IndentStyle; + } + + export interface FormatCodeSettings extends EditorSettings { + insertSpaceAfterCommaDelimiter?: boolean; + insertSpaceAfterSemicolonInForStatements?: boolean; + insertSpaceBeforeAndAfterBinaryOperators?: boolean; + insertSpaceAfterKeywordsInControlFlowStatements?: boolean; + insertSpaceAfterFunctionKeywordForAnonymousFunctions?: boolean; + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis?: boolean; + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets?: boolean; + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces?: boolean; + insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean; + placeOpenBraceOnNewLineForFunctions?: boolean; + placeOpenBraceOnNewLineForControlBlocks?: boolean; + } + + export interface CompilerOptions { + allowJs?: boolean; + allowSyntheticDefaultImports?: boolean; + allowUnreachableCode?: boolean; + allowUnusedLabels?: boolean; + baseUrl?: string; + charset?: string; + declaration?: boolean; + declarationDir?: string; + disableSizeLimit?: boolean; + emitBOM?: boolean; + emitDecoratorMetadata?: boolean; + experimentalDecorators?: boolean; + forceConsistentCasingInFileNames?: boolean; + inlineSourceMap?: boolean; + inlineSources?: boolean; + isolatedModules?: boolean; + jsx?: JsxEmit | ts.JsxEmit; + lib?: string[]; + locale?: string; + mapRoot?: string; + maxNodeModuleJsDepth?: number; + module?: ModuleKind | ts.ModuleKind; + moduleResolution?: ModuleResolutionKind | ts.ModuleResolutionKind; + newLine?: NewLineKind | ts.NewLineKind; + noEmit?: boolean; + noEmitHelpers?: boolean; + noEmitOnError?: boolean; + noErrorTruncation?: boolean; + noFallthroughCasesInSwitch?: boolean; + noImplicitAny?: boolean; + noImplicitReturns?: boolean; + noImplicitThis?: boolean; + noUnusedLocals?: boolean; + noUnusedParameters?: boolean; + noImplicitUseStrict?: boolean; + noLib?: boolean; + noResolve?: boolean; + out?: string; + outDir?: string; + outFile?: string; + paths?: MapLike; + preserveConstEnums?: boolean; + project?: string; + reactNamespace?: string; + removeComments?: boolean; + rootDir?: string; + rootDirs?: string[]; + skipLibCheck?: boolean; + skipDefaultLibCheck?: boolean; + sourceMap?: boolean; + sourceRoot?: string; + strictNullChecks?: boolean; + suppressExcessPropertyErrors?: boolean; + suppressImplicitAnyIndexErrors?: boolean; + target?: ScriptTarget | ts.ScriptTarget; + traceResolution?: boolean; + types?: string[]; + /** Paths used to used to compute primary types search locations */ + typeRoots?: string[]; + [option: string]: CompilerOptionsValue | undefined; + } + + export namespace JsxEmit { + export type None = "None"; + export type Preserve = "Preserve"; + export type React = "React"; + } + + export type JsxEmit = JsxEmit.None | JsxEmit.Preserve | JsxEmit.React; + + export namespace ModuleKind { + export type None = "None"; + export type CommonJS = "CommonJS"; + export type AMD = "AMD"; + export type UMD = "UMD"; + export type System = "System"; + export type ES6 = "ES6"; + export type ES2015 = "ES2015"; + } + + export type ModuleKind = ModuleKind.None | ModuleKind.CommonJS | ModuleKind.AMD | ModuleKind.UMD | ModuleKind.System | ModuleKind.ES6 | ModuleKind.ES2015; + + export namespace ModuleResolutionKind { + export type Classic = "Classic"; + export type Node = "Node"; + } + + export type ModuleResolutionKind = ModuleResolutionKind.Classic | ModuleResolutionKind.Node; + + export namespace NewLineKind { + export type Crlf = "Crlf"; + export type Lf = "Lf"; + } + + export type NewLineKind = NewLineKind.Crlf | NewLineKind.Lf; + + export namespace ScriptTarget { + export type ES3 = "ES3"; + export type ES5 = "ES5"; + export type ES6 = "ES6"; + export type ES2015 = "ES2015"; + } + + export type ScriptTarget = ScriptTarget.ES3 | ScriptTarget.ES5 | ScriptTarget.ES6 | ScriptTarget.ES2015; } diff --git a/src/server/session.ts b/src/server/session.ts index 3df6a1acb5126..bf179c907732f 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -807,7 +807,7 @@ namespace ts.server { private getIndentation(args: protocol.IndentationRequestArgs) { const { file, project } = this.getFileAndProjectWithoutRefreshingInferredProjects(args); const position = this.getPosition(args, project.getScriptInfoForNormalizedPath(file)); - const options = args.options || this.projectService.getFormatCodeOptions(file); + const options = args.options ? convertFormatOptions(args.options) : this.projectService.getFormatCodeOptions(file); const indentation = project.getLanguageService(/*ensureSynchronized*/ false).getIndentationAtPosition(file, position, options); return { position, indentation }; } @@ -874,19 +874,19 @@ namespace ts.server { private getFormattingEditsForRangeFull(args: protocol.FormatRequestArgs) { const { file, project } = this.getFileAndProjectWithoutRefreshingInferredProjects(args); - const options = args.options || this.projectService.getFormatCodeOptions(file); + const options = args.options ? convertFormatOptions(args.options) : this.projectService.getFormatCodeOptions(file); return project.getLanguageService(/*ensureSynchronized*/ false).getFormattingEditsForRange(file, args.position, args.endPosition, options); } private getFormattingEditsForDocumentFull(args: protocol.FormatRequestArgs) { const { file, project } = this.getFileAndProjectWithoutRefreshingInferredProjects(args); - const options = args.options || this.projectService.getFormatCodeOptions(file); + const options = args.options ? convertFormatOptions(args.options) : this.projectService.getFormatCodeOptions(file); return project.getLanguageService(/*ensureSynchronized*/ false).getFormattingEditsForDocument(file, options); } private getFormattingEditsAfterKeystrokeFull(args: protocol.FormatOnKeyRequestArgs) { const { file, project } = this.getFileAndProjectWithoutRefreshingInferredProjects(args); - const options = args.options || this.projectService.getFormatCodeOptions(file); + const options = args.options ? convertFormatOptions(args.options) : this.projectService.getFormatCodeOptions(file); return project.getLanguageService(/*ensureSynchronized*/ false).getFormattingEditsAfterKeystroke(file, args.position, args.key, options); } @@ -1426,24 +1426,8 @@ namespace ts.server { [CommandNames.RenameInfoFull]: (request: protocol.FileLocationRequest) => { return this.requiredResponse(this.getRenameInfo(request.arguments)); }, - [CommandNames.Open]: (request: protocol.Request) => { - const openArgs = request.arguments; - let scriptKind: ScriptKind; - switch (openArgs.scriptKindName) { - case "TS": - scriptKind = ScriptKind.TS; - break; - case "JS": - scriptKind = ScriptKind.JS; - break; - case "TSX": - scriptKind = ScriptKind.TSX; - break; - case "JSX": - scriptKind = ScriptKind.JSX; - break; - } - this.openClientFile(toNormalizedPath(openArgs.file), openArgs.fileContent, scriptKind); + [CommandNames.Open]: (request: protocol.OpenRequest) => { + this.openClientFile(toNormalizedPath(request.arguments.file), request.arguments.fileContent, convertScriptKindName(request.arguments.scriptKindName)); return this.notRequired(); }, [CommandNames.Quickinfo]: (request: protocol.QuickInfoRequest) => {