diff --git a/Jakefile.js b/Jakefile.js index 94358ab5429..cdc2fce7833 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -134,7 +134,7 @@ var serverCoreSources = [ "lsHost.ts", "project.ts", "editorServices.ts", - "protocol.d.ts", + "protocol.ts", "session.ts", "server.ts" ].map(function (f) { @@ -158,14 +158,13 @@ var typingsInstallerSources = [ var serverSources = serverCoreSources.concat(servicesSources); var languageServiceLibrarySources = [ - "protocol.d.ts", + "protocol.ts", "utilities.ts", "scriptVersionCache.ts", "scriptInfo.ts", "lsHost.ts", "project.ts", "editorServices.ts", - "protocol.d.ts", "session.ts", ].map(function (f) { @@ -218,7 +217,7 @@ var harnessSources = harnessCoreSources.concat([ ].map(function (f) { return path.join(unittestsDirectory, f); })).concat([ - "protocol.d.ts", + "protocol.ts", "utilities.ts", "scriptVersionCache.ts", "scriptInfo.ts", @@ -226,7 +225,6 @@ var harnessSources = harnessCoreSources.concat([ "project.ts", "typingsCache.ts", "editorServices.ts", - "protocol.d.ts", "session.ts", ].map(function (f) { return path.join(serverDirectory, f); @@ -474,6 +472,40 @@ compileFile(processDiagnosticMessagesJs, [], /*useBuiltCompiler*/ false); +var buildProtocolTs = path.join(scriptsDirectory, "buildProtocol.ts"); +var buildProtocolJs = path.join(scriptsDirectory, "buildProtocol.js"); +var buildProtocolDts = path.join(builtLocalDirectory, "protocol.d.ts"); +var typescriptServicesDts = path.join(builtLocalDirectory, "typescriptServices.d.ts"); + +file(buildProtocolTs); + +compileFile(buildProtocolJs, + [buildProtocolTs], + [buildProtocolTs], + [], + /*useBuiltCompiler*/ false, + {noOutFile: true}); + +file(buildProtocolDts, [buildProtocolTs, buildProtocolJs, typescriptServicesDts], function() { + + var protocolTs = path.join(serverDirectory, "protocol.ts"); + + var cmd = host + " " + buildProtocolJs + " "+ protocolTs + " " + typescriptServicesDts + " " + buildProtocolDts; + console.log(cmd); + var ex = jake.createExec([cmd]); + // Add listeners for output and error + ex.addListener("stdout", function (output) { + process.stdout.write(output); + }); + ex.addListener("stderr", function (error) { + process.stderr.write(error); + }); + ex.addListener("cmdEnd", function () { + complete(); + }); + ex.run(); +}, { async: true }) + // The generated diagnostics map; built for the compiler and for the 'generate-diagnostics' task file(diagnosticInfoMapTs, [processDiagnosticMessagesJs, diagnosticMessagesJson], function () { var cmd = host + " " + processDiagnosticMessagesJs + " " + diagnosticMessagesJson; @@ -611,6 +643,8 @@ compileFile( inlineSourceMap: true }); +file(typescriptServicesDts, [servicesFile]); + var cancellationTokenFile = path.join(builtLocalDirectory, "cancellationToken.js"); compileFile(cancellationTokenFile, cancellationTokenSources, [builtLocalDirectory].concat(cancellationTokenSources), /*prefixes*/ [copyright], /*useBuiltCompiler*/ true, { outDir: builtLocalDirectory, noOutFile: true }); @@ -645,7 +679,7 @@ task("build-fold-end", [], function () { // Local target to build the compiler and services desc("Builds the full compiler and services"); -task("local", ["build-fold-start", "generate-diagnostics", "lib", tscFile, servicesFile, nodeDefinitionsFile, serverFile, builtGeneratedDiagnosticMessagesJSON, "lssl", "build-fold-end"]); +task("local", ["build-fold-start", "generate-diagnostics", "lib", tscFile, servicesFile, nodeDefinitionsFile, serverFile, buildProtocolDts, builtGeneratedDiagnosticMessagesJSON, "lssl", "build-fold-end"]); // Local target to build only tsc.js desc("Builds only the compiler"); diff --git a/scripts/buildProtocol.ts b/scripts/buildProtocol.ts new file mode 100644 index 00000000000..8d49262a470 --- /dev/null +++ b/scripts/buildProtocol.ts @@ -0,0 +1,143 @@ +/// + +import * as ts from "../lib/typescript"; +import * as path from "path"; + +function endsWith(s: string, suffix: string) { + return s.lastIndexOf(suffix, s.length - suffix.length) !== -1; +} + +class DeclarationsWalker { + private visitedTypes: ts.Type[] = []; + private text = ""; + private constructor(private typeChecker: ts.TypeChecker, private protocolFile: ts.SourceFile) { + } + + static getExtraDeclarations(typeChecker: ts.TypeChecker, protocolFile: ts.SourceFile): string { + let text = "declare namespace ts.server.protocol {\n"; + var walker = new DeclarationsWalker(typeChecker, protocolFile); + walker.visitTypeNodes(protocolFile); + return walker.text + ? `declare namespace ts.server.protocol {\n${walker.text}}` + : ""; + } + + private processType(type: ts.Type): void { + if (this.visitedTypes.indexOf(type) >= 0) { + return; + } + this.visitedTypes.push(type); + let s = type.aliasSymbol || type.getSymbol(); + if (!s) { + return; + } + if (s.name === "Array") { + // we should process type argument instead + return this.processType((type).typeArguments[0]); + } + else { + for (const decl of s.getDeclarations()) { + const sourceFile = decl.getSourceFile(); + if (sourceFile === this.protocolFile || path.basename(sourceFile.fileName) === "lib.d.ts") { + return; + } + // splice declaration in final d.ts file + const text = decl.getFullText(); + this.text += `${text}\n`; + + // recursively pull all dependencies into result dts file + this.visitTypeNodes(decl); + } + } + } + + private visitTypeNodes(node: ts.Node) { + if (node.parent) { + switch (node.parent.kind) { + case ts.SyntaxKind.VariableDeclaration: + case ts.SyntaxKind.MethodDeclaration: + case ts.SyntaxKind.MethodSignature: + case ts.SyntaxKind.PropertyDeclaration: + case ts.SyntaxKind.PropertySignature: + 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); + } + } + break; + } + } + ts.forEachChild(node, n => this.visitTypeNodes(n)); + } +} + +function generateProtocolFile(protocolTs: string, typeScriptServicesDts: string): string { + const options = { target: ts.ScriptTarget.ES5, declaration: true, noResolve: true, types: [], stripInternal: true }; + + /** + * 1st pass - generate a program from protocol.ts and typescriptservices.d.ts and emit core version of protocol.d.ts with all internal members stripped + * @return text of protocol.d.t.s + */ + function getInitialDtsFileForProtocol() { + const program = ts.createProgram([protocolTs, typeScriptServicesDts], options); + + let protocolDts: string; + program.emit(program.getSourceFile(protocolTs), (file, content) => { + if (endsWith(file, ".d.ts")) { + protocolDts = content; + } + }); + if (protocolDts === undefined) { + throw new Error(`Declaration file for protocol.ts is not generated`) + } + return protocolDts; + } + + const protocolFileName = "protocol.d.ts"; + /** + * Second pass - generate a program from protocol.d.ts and typescriptservices.d.ts, then augment core protocol.d.ts with extra types from typescriptservices.d.ts + */ + function getProgramWithProtocolText(protocolDts: string, includeTypeScriptServices: boolean) { + const host = ts.createCompilerHost(options); + const originalGetSourceFile = host.getSourceFile; + host.getSourceFile = (fileName) => { + if (fileName === protocolFileName) { + return ts.createSourceFile(fileName, protocolDts, options.target); + } + return originalGetSourceFile.apply(host, [fileName]); + } + const rootFiles = includeTypeScriptServices ? [protocolFileName, typeScriptServicesDts] : [protocolFileName]; + return ts.createProgram(rootFiles, options, host); + } + + let protocolDts = getInitialDtsFileForProtocol(); + const program = getProgramWithProtocolText(protocolDts, /*includeTypeScriptServices*/ true); + + const protocolFile = program.getSourceFile("protocol.d.ts"); + const extraDeclarations = DeclarationsWalker.getExtraDeclarations(program.getTypeChecker(), protocolFile); + if (extraDeclarations) { + protocolDts += extraDeclarations; + } + // 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()]; + if (diagnostics.length) { + const flattenedDiagnostics = diagnostics.map(d => ts.flattenDiagnosticMessageText(d.messageText, "\n")).join("\n"); + throw new Error(`Unexpected errors during sanity check: ${flattenedDiagnostics}`); + } + return protocolDts; +} + +if (process.argv.length < 5) { + console.log(`Expected 3 arguments: path to 'protocol.ts', path to 'typescriptservices.d.ts' and path to output file`); + process.exit(1); +} + +const protocolTs = process.argv[2]; +const typeScriptServicesDts = process.argv[3]; +const outputFile = process.argv[4]; +const generatedProtocolDts = generateProtocolFile(protocolTs, typeScriptServicesDts); +ts.sys.writeFile(outputFile, generatedProtocolDts); diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 10bf9017891..90c189970d2 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -2574,11 +2574,7 @@ namespace ts { NodeJs = 2 } - export type RootPaths = string[]; - export type PathSubstitutions = MapLike; - export type TsConfigOnlyOptions = RootPaths | PathSubstitutions; - - export type CompilerOptionsValue = string | number | boolean | (string | number)[] | TsConfigOnlyOptions; + export type CompilerOptionsValue = string | number | boolean | (string | number)[] | string[] | MapLike; export interface CompilerOptions { allowJs?: boolean; @@ -2629,14 +2625,14 @@ namespace ts { out?: string; outDir?: string; outFile?: string; - paths?: PathSubstitutions; + paths?: MapLike; preserveConstEnums?: boolean; project?: string; /* @internal */ pretty?: DiagnosticStyle; reactNamespace?: string; removeComments?: boolean; rootDir?: string; - rootDirs?: RootPaths; + rootDirs?: string[]; skipLibCheck?: boolean; skipDefaultLibCheck?: boolean; sourceMap?: boolean; diff --git a/src/server/builder.ts b/src/server/builder.ts index 639c41d2b63..475202a0aab 100644 --- a/src/server/builder.ts +++ b/src/server/builder.ts @@ -1,6 +1,5 @@ /// /// -/// /// /// diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index 707f286a9b5..d58bb416f26 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1,6 +1,5 @@ /// /// -/// /// /// /// diff --git a/src/server/protocol.d.ts b/src/server/protocol.ts similarity index 87% rename from src/server/protocol.d.ts rename to src/server/protocol.ts index 973bede3303..c2c5e079a33 100644 --- a/src/server/protocol.d.ts +++ b/src/server/protocol.ts @@ -1,7 +1,90 @@ /** * Declaration module describing the TypeScript Server protocol */ -declare namespace ts.server.protocol { +namespace ts.server.protocol { + export namespace CommandNames { + export const Brace = "brace"; + /* @internal */ + export const BraceFull = "brace-full"; + export const BraceCompletion = "braceCompletion"; + export const Change = "change"; + export const Close = "close"; + export const Completions = "completions"; + /* @internal */ + export const CompletionsFull = "completions-full"; + export const CompletionDetails = "completionEntryDetails"; + export const CompileOnSaveAffectedFileList = "compileOnSaveAffectedFileList"; + export const CompileOnSaveEmitFile = "compileOnSaveEmitFile"; + export const Configure = "configure"; + export const Definition = "definition"; + /* @internal */ + export const DefinitionFull = "definition-full"; + export const Exit = "exit"; + export const Format = "format"; + export const Formatonkey = "formatonkey"; + /* @internal */ + export const FormatFull = "format-full"; + /* @internal */ + export const FormatonkeyFull = "formatonkey-full"; + /* @internal */ + export const FormatRangeFull = "formatRange-full"; + export const Geterr = "geterr"; + export const GeterrForProject = "geterrForProject"; + export const SemanticDiagnosticsSync = "semanticDiagnosticsSync"; + export const SyntacticDiagnosticsSync = "syntacticDiagnosticsSync"; + export const NavBar = "navbar"; + /* @internal */ + export const NavBarFull = "navbar-full"; + export const Navto = "navto"; + /* @internal */ + export const NavtoFull = "navto-full"; + export const Occurrences = "occurrences"; + export const DocumentHighlights = "documentHighlights"; + /* @internal */ + export const DocumentHighlightsFull = "documentHighlights-full"; + export const Open = "open"; + export const Quickinfo = "quickinfo"; + /* @internal */ + export const QuickinfoFull = "quickinfo-full"; + export const References = "references"; + /* @internal */ + export const ReferencesFull = "references-full"; + export const Reload = "reload"; + export const Rename = "rename"; + /* @internal */ + export const RenameInfoFull = "rename-full"; + /* @internal */ + export const RenameLocationsFull = "renameLocations-full"; + export const Saveto = "saveto"; + export const SignatureHelp = "signatureHelp"; + /* @internal */ + export const SignatureHelpFull = "signatureHelp-full"; + export const TypeDefinition = "typeDefinition"; + export const ProjectInfo = "projectInfo"; + export const ReloadProjects = "reloadProjects"; + export const Unknown = "unknown"; + export const OpenExternalProject = "openExternalProject"; + export const OpenExternalProjects = "openExternalProjects"; + export const CloseExternalProject = "closeExternalProject"; + export const SynchronizeProjectList = "synchronizeProjectList"; + /* @internal */ + export const ApplyChangedToOpenFiles = "applyChangedToOpenFiles"; + /* @internal */ + export const EncodedSemanticClassificationsFull = "encodedSemanticClassifications-full"; + export const Cleanup = "cleanup"; + export const OutliningSpans = "outliningSpans"; + export const TodoComments = "todoComments"; + export const Indentation = "indentation"; + export const DocCommentTemplate = "docCommentTemplate"; + /* @internal */ + export const CompilerOptionsDiagnosticsFull = "compilerOptionsDiagnostics-full"; + /* @internal */ + export const NameOrDottedNameSpan = "nameOrDottedNameSpan"; + /* @internal */ + export const BreakpointStatement = "breakpointStatement"; + export const CompilerOptionsForInferredProjects = "compilerOptionsForInferredProjects"; + } + /** * A TypeScript Server message */ @@ -190,16 +273,17 @@ declare namespace ts.server.protocol { /** * The line number for the request (1-based). */ - line?: number; + line: number; /** * The character offset (on the line) for the request (1-based). */ - offset?: number; + offset: number; /** * Position (can be specified instead of line/offset pair) */ + /* @internal */ position?: number; } @@ -539,70 +623,12 @@ declare namespace ts.server.protocol { projectErrors: DiagnosticWithLinePosition[]; } + /* @internal */ export interface ChangedOpenFile { fileName: string; changes: ts.TextChange[]; } - /** - * Editor options - */ - export interface EditorOptions { - - /** Number of spaces for each tab. Default value is 4. */ - tabSize?: number; - - /** Number of spaces to indent during formatting. Default value is 4. */ - indentSize?: number; - - /** Number of additional spaces to indent during formatting to preserve base indentation (ex. script block indentation). Default value is 0. */ - baseIndentSize?: number; - - /** The new line character to be used. Default value is the OS line delimiter. */ - newLineCharacter?: string; - - /** Whether tabs should be converted to spaces. Default value is true. */ - convertTabsToSpaces?: boolean; - } - - /** - * Format options - */ - export interface FormatOptions extends EditorOptions { - - /** Defines space handling after a comma delimiter. Default value is true. */ - insertSpaceAfterCommaDelimiter?: boolean; - - /** Defines space handling after a semicolon in a for statement. Default value is true */ - insertSpaceAfterSemicolonInForStatements?: boolean; - - /** Defines space handling after a binary operator. Default value is true. */ - insertSpaceBeforeAndAfterBinaryOperators?: boolean; - - /** Defines space handling after keywords in control flow statement. Default value is true. */ - insertSpaceAfterKeywordsInControlFlowStatements?: boolean; - - /** Defines space handling after function keyword for anonymous functions. Default value is false. */ - insertSpaceAfterFunctionKeywordForAnonymousFunctions?: boolean; - - /** Defines space handling after opening and before closing non empty parenthesis. Default value is false. */ - insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis?: boolean; - - /** Defines space handling after opening and before closing non empty brackets. Default value is false. */ - insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets?: boolean; - - /** Defines space handling before and after template string braces. Default value is false. */ - insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces?: boolean; - - /** Defines space handling before and after JSX expression braces. Default value is false. */ - insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean; - - /** Defines whether an open brace is put onto a new line for functions or not. Default value is false. */ - placeOpenBraceOnNewLineForFunctions?: boolean; - - /** Defines whether an open brace is put onto a new line for control blocks or not. Default value is false. */ - placeOpenBraceOnNewLineForControlBlocks?: boolean; - } /** * Information found in a configure request. @@ -623,7 +649,7 @@ declare namespace ts.server.protocol { /** * The format options to use during formatting and other code editing features. */ - formatOptions?: FormatOptions; + formatOptions?: FormatCodeSettings; } /** @@ -669,7 +695,7 @@ declare namespace ts.server.protocol { arguments: OpenRequestArgs; } - type OpenExternalProjectArgs = ExternalProject; + export type OpenExternalProjectArgs = ExternalProject; export interface OpenExternalProjectRequest extends Request { arguments: OpenExternalProjectArgs; @@ -699,10 +725,12 @@ declare namespace ts.server.protocol { knownProjects: protocol.ProjectVersionInfo[]; } + /* @internal */ export interface ApplyChangedToOpenFilesRequest extends Request { arguments: ApplyChangedToOpenFilesRequestArgs; } + /* @internal */ export interface ApplyChangedToOpenFilesRequestArgs { openFiles?: ExternalFile[]; changedFiles?: ChangedOpenFile[]; @@ -820,7 +848,7 @@ declare namespace ts.server.protocol { endOffset: number; endPosition?: number; - options?: ts.FormatCodeOptions; + options?: FormatCodeSettings; } /** @@ -875,7 +903,7 @@ declare namespace ts.server.protocol { */ key: string; - options?: ts.FormatCodeOptions; + options?: FormatCodeSettings; } /** diff --git a/src/server/scriptInfo.ts b/src/server/scriptInfo.ts index 410382a9ca4..b068fbddf65 100644 --- a/src/server/scriptInfo.ts +++ b/src/server/scriptInfo.ts @@ -91,7 +91,7 @@ namespace ts.server { return this.containingProjects[0]; } - setFormatOptions(formatSettings: protocol.FormatOptions): void { + setFormatOptions(formatSettings: FormatCodeSettings): void { if (formatSettings) { if (!this.formatCodeSettings) { this.formatCodeSettings = getDefaultFormatCodeSettings(this.host); diff --git a/src/server/scriptVersionCache.ts b/src/server/scriptVersionCache.ts index 1508187c13e..8d0efa081ad 100644 --- a/src/server/scriptVersionCache.ts +++ b/src/server/scriptVersionCache.ts @@ -1,6 +1,5 @@ /// /// -/// /// namespace ts.server { diff --git a/src/server/session.ts b/src/server/session.ts index 6c13e3a5e78..a3f06c93aca 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1,6 +1,6 @@ /// /// -/// +/// /// namespace ts.server { @@ -70,69 +70,7 @@ namespace ts.server { return true; } - export namespace CommandNames { - export const Brace = "brace"; - export const BraceFull = "brace-full"; - export const BraceCompletion = "braceCompletion"; - export const Change = "change"; - export const Close = "close"; - export const Completions = "completions"; - export const CompletionsFull = "completions-full"; - export const CompletionDetails = "completionEntryDetails"; - export const CompileOnSaveAffectedFileList = "compileOnSaveAffectedFileList"; - export const CompileOnSaveEmitFile = "compileOnSaveEmitFile"; - export const Configure = "configure"; - export const Definition = "definition"; - export const DefinitionFull = "definition-full"; - export const Exit = "exit"; - export const Format = "format"; - export const Formatonkey = "formatonkey"; - export const FormatFull = "format-full"; - export const FormatonkeyFull = "formatonkey-full"; - export const FormatRangeFull = "formatRange-full"; - export const Geterr = "geterr"; - export const GeterrForProject = "geterrForProject"; - export const SemanticDiagnosticsSync = "semanticDiagnosticsSync"; - export const SyntacticDiagnosticsSync = "syntacticDiagnosticsSync"; - export const NavBar = "navbar"; - export const NavBarFull = "navbar-full"; - export const Navto = "navto"; - export const NavtoFull = "navto-full"; - export const Occurrences = "occurrences"; - export const DocumentHighlights = "documentHighlights"; - export const DocumentHighlightsFull = "documentHighlights-full"; - export const Open = "open"; - export const Quickinfo = "quickinfo"; - export const QuickinfoFull = "quickinfo-full"; - export const References = "references"; - export const ReferencesFull = "references-full"; - export const Reload = "reload"; - export const Rename = "rename"; - export const RenameInfoFull = "rename-full"; - export const RenameLocationsFull = "renameLocations-full"; - export const Saveto = "saveto"; - export const SignatureHelp = "signatureHelp"; - export const SignatureHelpFull = "signatureHelp-full"; - export const TypeDefinition = "typeDefinition"; - export const ProjectInfo = "projectInfo"; - export const ReloadProjects = "reloadProjects"; - export const Unknown = "unknown"; - export const OpenExternalProject = "openExternalProject"; - export const OpenExternalProjects = "openExternalProjects"; - export const CloseExternalProject = "closeExternalProject"; - export const SynchronizeProjectList = "synchronizeProjectList"; - export const ApplyChangedToOpenFiles = "applyChangedToOpenFiles"; - export const EncodedSemanticClassificationsFull = "encodedSemanticClassifications-full"; - export const Cleanup = "cleanup"; - export const OutliningSpans = "outliningSpans"; - export const TodoComments = "todoComments"; - export const Indentation = "indentation"; - export const DocCommentTemplate = "docCommentTemplate"; - export const CompilerOptionsDiagnosticsFull = "compilerOptionsDiagnostics-full"; - export const NameOrDottedNameSpan = "nameOrDottedNameSpan"; - export const BreakpointStatement = "breakpointStatement"; - export const CompilerOptionsForInferredProjects = "compilerOptionsForInferredProjects"; - } + import CommandNames = protocol.CommandNames; export function formatMessage(msg: T, logger: server.Logger, byteLength: (s: string, encoding: string) => number, newLine: string): string { const verboseLogging = logger.hasLevel(LogLevel.verbose); diff --git a/src/server/tsconfig.json b/src/server/tsconfig.json index bd9bb14ba41..27bacc0dfbf 100644 --- a/src/server/tsconfig.json +++ b/src/server/tsconfig.json @@ -22,7 +22,7 @@ "typingsCache.ts", "project.ts", "editorServices.ts", - "protocol.d.ts", + "protocol.ts", "session.ts", "server.ts" ]