diff --git a/Jakefile.js b/Jakefile.js index 64a8553ef39..b548a0d3dd8 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -174,7 +174,7 @@ var serverCoreSources = [ "lsHost.ts", "project.ts", "editorServices.ts", - "protocol.d.ts", + "protocol.ts", "session.ts", "server.ts" ].map(function (f) { @@ -198,14 +198,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) { @@ -259,7 +258,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", @@ -267,7 +266,6 @@ var harnessSources = harnessCoreSources.concat([ "project.ts", "typingsCache.ts", "editorServices.ts", - "protocol.d.ts", "session.ts", ].map(function (f) { return path.join(serverDirectory, f); @@ -518,6 +516,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; @@ -655,6 +687,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 }); @@ -689,7 +723,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"); @@ -745,7 +779,7 @@ task("generate-spec", [specMd]); // Makes a new LKG. This target does not build anything, but errors if not all the outputs are present in the built/local directory desc("Makes a new LKG out of the built js files"); task("LKG", ["clean", "release", "local"].concat(libraryTargets), function () { - var expectedFiles = [tscFile, servicesFile, serverFile, nodePackageFile, nodeDefinitionsFile, standaloneDefinitionsFile, tsserverLibraryFile, tsserverLibraryDefinitionFile, cancellationTokenFile, typingsInstallerFile].concat(libraryTargets); + var expectedFiles = [tscFile, servicesFile, serverFile, nodePackageFile, nodeDefinitionsFile, standaloneDefinitionsFile, tsserverLibraryFile, tsserverLibraryDefinitionFile, cancellationTokenFile, typingsInstallerFile, buildProtocolDts].concat(libraryTargets); var missingFiles = expectedFiles.filter(function (f) { return !fs.existsSync(f); }); diff --git a/lib/lib.d.ts b/lib/lib.d.ts index 586b3675305..d8be920dc0a 100644 --- a/lib/lib.d.ts +++ b/lib/lib.d.ts @@ -260,6 +260,9 @@ interface Function { */ bind(this: Function, thisArg: any, ...argArray: any[]): any; + /** Returns a string representation of an object. */ + toString(): string; + prototype: any; readonly length: number; 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/binder.ts b/src/compiler/binder.ts index b17fe546f58..b2225e9333c 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -84,6 +84,7 @@ namespace ts { IsFunctionExpression = 1 << 4, HasLocals = 1 << 5, IsInterface = 1 << 6, + IsObjectLiteralOrClassExpressionMethod = 1 << 7, } const binder = createBinder(); @@ -486,8 +487,8 @@ namespace ts { } else { currentFlow = { flags: FlowFlags.Start }; - if (containerFlags & ContainerFlags.IsFunctionExpression) { - (currentFlow).container = node; + if (containerFlags & (ContainerFlags.IsFunctionExpression | ContainerFlags.IsObjectLiteralOrClassExpressionMethod)) { + (currentFlow).container = node; } currentReturnTarget = undefined; } @@ -1237,9 +1238,12 @@ namespace ts { case SyntaxKind.SourceFile: return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals; + case SyntaxKind.MethodDeclaration: + if (isObjectLiteralOrClassExpressionMethod(node)) { + return ContainerFlags.IsContainer | ContainerFlags.IsControlFlowContainer | ContainerFlags.HasLocals | ContainerFlags.IsFunctionLike | ContainerFlags.IsObjectLiteralOrClassExpressionMethod; + } case SyntaxKind.Constructor: case SyntaxKind.FunctionDeclaration: - case SyntaxKind.MethodDeclaration: case SyntaxKind.MethodSignature: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: @@ -2238,6 +2242,10 @@ namespace ts { } } + if (currentFlow && isObjectLiteralOrClassExpressionMethod(node)) { + node.flowNode = currentFlow; + } + return hasDynamicName(node) ? bindAnonymousDeclaration(node, symbolFlags, "__computed") : declareSymbolAndAddToSymbolTable(node, symbolFlags, symbolExcludes); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index dfe6317e250..40332674567 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -922,7 +922,7 @@ namespace ts { if (result && isInExternalModule && (meaning & SymbolFlags.Value) === SymbolFlags.Value) { const decls = result.declarations; if (decls && decls.length === 1 && decls[0].kind === SyntaxKind.NamespaceExportDeclaration) { - error(errorLocation, Diagnostics.Identifier_0_must_be_imported_from_a_module, name); + error(errorLocation, Diagnostics._0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead, name); } } } @@ -1465,6 +1465,10 @@ namespace ts { function getExportsForModule(moduleSymbol: Symbol): SymbolTable { const visitedSymbols: Symbol[] = []; + + // A module defined by an 'export=' consists on one export that needs to be resolved + moduleSymbol = resolveExternalModuleSymbol(moduleSymbol); + return visit(moduleSymbol) || moduleSymbol.exports; // The ES6 spec permits export * declarations in a module to circularly reference the module itself. For example, @@ -8457,6 +8461,28 @@ namespace ts { return f(type) ? type : neverType; } + function mapType(type: Type, f: (t: Type) => Type): Type { + return type.flags & TypeFlags.Union ? getUnionType(map((type).types, f)) : f(type); + } + + function extractTypesOfKind(type: Type, kind: TypeFlags) { + return filterType(type, t => (t.flags & kind) !== 0); + } + + // Return a new type in which occurrences of the string and number primitive types in + // typeWithPrimitives have been replaced with occurrences of string literals and numeric + // literals in typeWithLiterals, respectively. + function replacePrimitivesWithLiterals(typeWithPrimitives: Type, typeWithLiterals: Type) { + if (isTypeSubsetOf(stringType, typeWithPrimitives) && maybeTypeOfKind(typeWithLiterals, TypeFlags.StringLiteral) || + isTypeSubsetOf(numberType, typeWithPrimitives) && maybeTypeOfKind(typeWithLiterals, TypeFlags.NumberLiteral)) { + return mapType(typeWithPrimitives, t => + t.flags & TypeFlags.String ? extractTypesOfKind(typeWithLiterals, TypeFlags.String | TypeFlags.StringLiteral) : + t.flags & TypeFlags.Number ? extractTypesOfKind(typeWithLiterals, TypeFlags.Number | TypeFlags.NumberLiteral) : + t); + } + return typeWithPrimitives; + } + function isIncomplete(flowType: FlowType) { return flowType.flags === 0; } @@ -8792,7 +8818,7 @@ namespace ts { } if (assumeTrue) { const narrowedType = filterType(type, t => areTypesComparable(t, valueType)); - return narrowedType.flags & TypeFlags.Never ? type : narrowedType; + return narrowedType.flags & TypeFlags.Never ? type : replacePrimitivesWithLiterals(narrowedType, valueType); } if (isUnitType(valueType)) { const regularType = getRegularTypeOfLiteralType(valueType); @@ -8839,7 +8865,9 @@ namespace ts { const clauseTypes = switchTypes.slice(clauseStart, clauseEnd); const hasDefaultClause = clauseStart === clauseEnd || contains(clauseTypes, neverType); const discriminantType = getUnionType(clauseTypes); - const caseType = discriminantType.flags & TypeFlags.Never ? neverType : filterType(type, t => isTypeComparableTo(discriminantType, t)); + const caseType = + discriminantType.flags & TypeFlags.Never ? neverType : + replacePrimitivesWithLiterals(filterType(type, t => isTypeComparableTo(discriminantType, t)), discriminantType); if (!hasDefaultClause) { return caseType; } @@ -9163,7 +9191,9 @@ namespace ts { // a const variable or parameter from an outer function, we extend the origin of the control flow // analysis to include the immediately enclosing function. while (flowContainer !== declarationContainer && - (flowContainer.kind === SyntaxKind.FunctionExpression || flowContainer.kind === SyntaxKind.ArrowFunction) && + (flowContainer.kind === SyntaxKind.FunctionExpression || + flowContainer.kind === SyntaxKind.ArrowFunction || + isObjectLiteralOrClassExpressionMethod(flowContainer)) && (isReadonlySymbol(localOrExportSymbol) || isParameter && !isParameterAssigned(localOrExportSymbol))) { flowContainer = getControlFlowContainer(flowContainer); } @@ -17889,7 +17919,8 @@ namespace ts { } function isNotOverload(declaration: Declaration): boolean { - return declaration.kind !== SyntaxKind.FunctionDeclaration || !!(declaration as FunctionDeclaration).body; + return (declaration.kind !== SyntaxKind.FunctionDeclaration && declaration.kind !== SyntaxKind.MethodDeclaration) || + !!(declaration as FunctionDeclaration).body; } } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 648447ac26a..72dd42b3997 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -975,7 +975,7 @@ namespace ts { basePath: string, errors: Diagnostic[], configFileName?: string): CompilerOptions { const options: CompilerOptions = getBaseFileName(configFileName) === "jsconfig.json" - ? { allowJs: true, maxNodeModuleJsDepth: 2, allowSyntheticDefaultImports: true } + ? { allowJs: true, maxNodeModuleJsDepth: 2, allowSyntheticDefaultImports: true, skipLibCheck: true } : {}; convertOptionsFromJson(optionDeclarations, jsonOptions, basePath, options, Diagnostics.Unknown_compiler_option_0, errors); return options; diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 1b8c995ea05..554bcc50865 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1923,7 +1923,7 @@ "category": "Error", "code": 2685 }, - "Identifier '{0}' must be imported from a module": { + "'{0}' refers to a UMD global, but the current file is a module. Consider adding an import instead.": { "category": "Error", "code": 2686 }, diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index e7b3872f2e3..b79106766da 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -1190,7 +1190,7 @@ namespace ts { } function scanBinaryOrOctalDigits(base: number): number { - Debug.assert(base !== 2 || base !== 8, "Expected either base 2 or base 8"); + Debug.assert(base === 2 || base === 8, "Expected either base 2 or base 8"); let value = 0; // For counting number of digits; Valid binaryIntegerLiteral must have at least one binary digit following B or b. diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 7cf7d75bc02..1efa1e2b010 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -476,6 +476,10 @@ namespace ts { // Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows // (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643) let options: any; + if (!directoryExists(directoryName)) { + return; + } + if (isNode4OrLater() && (process.platform === "win32" || process.platform === "darwin")) { options = { persistent: true, recursive: !!recursive }; } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 638504e613f..34f4b0000f8 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1922,7 +1922,7 @@ namespace ts { // function, the container property references the function (which in turn has a flowNode // property for the containing control flow). export interface FlowStart extends FlowNode { - container?: FunctionExpression | ArrowFunction; + container?: FunctionExpression | ArrowFunction | MethodDeclaration; } // FlowLabel represents a junction with multiple possible preceding control flows. @@ -2644,7 +2644,7 @@ namespace ts { // 'Narrowable' types are types where narrowing actually narrows. // This *should* be every type other than null, undefined, void, and never Narrowable = Any | StructuredType | TypeParameter | StringLike | NumberLike | BooleanLike | ESSymbol, - NotUnionOrUnit = Any | String | Number | ESSymbol | ObjectType, + NotUnionOrUnit = Any | ESSymbol | ObjectType, /* @internal */ RequiresWidening = ContainsWideningType | ContainsObjectLiteral, /* @internal */ @@ -2917,11 +2917,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; @@ -2973,14 +2969,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/compiler/utilities.ts b/src/compiler/utilities.ts index 558015bb0e3..498c195ea3a 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -895,6 +895,12 @@ namespace ts { return node && node.kind === SyntaxKind.MethodDeclaration && node.parent.kind === SyntaxKind.ObjectLiteralExpression; } + export function isObjectLiteralOrClassExpressionMethod(node: Node): node is MethodDeclaration { + return node.kind === SyntaxKind.MethodDeclaration && + (node.parent.kind === SyntaxKind.ObjectLiteralExpression || + node.parent.kind === SyntaxKind.ClassExpression); + } + export function isIdentifierTypePredicate(predicate: TypePredicate): predicate is IdentifierTypePredicate { return predicate && predicate.kind === TypePredicateKind.Identifier; } diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index f54804c0eb5..af10f355e1f 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -2255,6 +2255,18 @@ namespace FourSlash { } } + public verifyNavigationTree(json: any) { + const tree = this.languageService.getNavigationTree(this.activeFile.fileName); + if (JSON.stringify(tree, replacer) !== JSON.stringify(json)) { + this.raiseError(`verifyNavigationTree failed - expected: ${stringify(json)}, got: ${stringify(tree, replacer)}`); + } + + function replacer(key: string, value: any) { + // Don't check "spans", and omit falsy values. + return key === "spans" ? undefined : (value || undefined); + } + } + public printNavigationItems(searchValue: string) { const items = this.languageService.getNavigateToItems(searchValue); const length = items && items.length; @@ -3343,6 +3355,10 @@ namespace FourSlashInterface { this.state.verifyNavigationBar(json); } + public navigationTree(json: any) { + this.state.verifyNavigationTree(json); + } + public navigationItemsListCount(count: number, searchValue: string, matchKind?: string, fileName?: string) { this.state.verifyNavigationItemsCount(count, searchValue, matchKind, fileName); } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 99cee7dbd41..7cc4c2044ef 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -459,6 +459,10 @@ namespace Harness.LanguageService { getNavigationBarItems(fileName: string): ts.NavigationBarItem[] { return unwrapJSONCallResult(this.shim.getNavigationBarItems(fileName)); } + getNavigationTree(fileName: string): ts.NavigationTree { + return unwrapJSONCallResult(this.shim.getNavigationTree(fileName)); + } + getOutliningSpans(fileName: string): ts.OutliningSpan[] { return unwrapJSONCallResult(this.shim.getOutliningSpans(fileName)); } diff --git a/src/harness/unittests/compileOnSave.ts b/src/harness/unittests/compileOnSave.ts index 24fd47ee0cb..797268000eb 100644 --- a/src/harness/unittests/compileOnSave.ts +++ b/src/harness/unittests/compileOnSave.ts @@ -3,6 +3,8 @@ /// namespace ts.projectSystem { + import CommandNames = server.CommandNames; + function createTestTypingsInstaller(host: server.ServerHost) { return new TestTypingsInstaller("/a/data/", /*throttleLimit*/5, host); } @@ -75,7 +77,7 @@ namespace ts.projectSystem { }; // Change the content of file1 to `export var T: number;export function Foo() { };` - changeModuleFile1ShapeRequest1 = makeSessionRequest(server.CommandNames.Change, { + changeModuleFile1ShapeRequest1 = makeSessionRequest(CommandNames.Change, { file: moduleFile1.path, line: 1, offset: 1, @@ -85,7 +87,7 @@ namespace ts.projectSystem { }); // Change the content of file1 to `export var T: number;export function Foo() { };` - changeModuleFile1InternalRequest1 = makeSessionRequest(server.CommandNames.Change, { + changeModuleFile1InternalRequest1 = makeSessionRequest(CommandNames.Change, { file: moduleFile1.path, line: 1, offset: 1, @@ -95,7 +97,7 @@ namespace ts.projectSystem { }); // Change the content of file1 to `export var T: number;export function Foo() { };` - changeModuleFile1ShapeRequest2 = makeSessionRequest(server.CommandNames.Change, { + changeModuleFile1ShapeRequest2 = makeSessionRequest(CommandNames.Change, { file: moduleFile1.path, line: 1, offset: 1, @@ -104,7 +106,7 @@ namespace ts.projectSystem { insertString: `export var T2: number;` }); - moduleFile1FileListRequest = makeSessionRequest(server.CommandNames.CompileOnSaveAffectedFileList, { file: moduleFile1.path, projectFileName: configFile.path }); + moduleFile1FileListRequest = makeSessionRequest(CommandNames.CompileOnSaveAffectedFileList, { file: moduleFile1.path, projectFileName: configFile.path }); }); it("should contains only itself if a module file's shape didn't change, and all files referencing it if its shape changed", () => { @@ -120,7 +122,7 @@ namespace ts.projectSystem { sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]); // Change the content of file1 to `export var T: number;export function Foo() { console.log('hi'); };` - const changeFile1InternalRequest = makeSessionRequest(server.CommandNames.Change, { + const changeFile1InternalRequest = makeSessionRequest(CommandNames.Change, { file: moduleFile1.path, line: 1, offset: 46, @@ -143,7 +145,7 @@ namespace ts.projectSystem { sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2] }]); // Change file2 content to `let y = Foo();` - const removeFile1Consumer1ImportRequest = makeSessionRequest(server.CommandNames.Change, { + const removeFile1Consumer1ImportRequest = makeSessionRequest(CommandNames.Change, { file: file1Consumer1.path, line: 1, offset: 1, @@ -156,7 +158,7 @@ namespace ts.projectSystem { sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer2] }]); // Add the import statements back to file2 - const addFile2ImportRequest = makeSessionRequest(server.CommandNames.Change, { + const addFile2ImportRequest = makeSessionRequest(CommandNames.Change, { file: file1Consumer1.path, line: 1, offset: 1, @@ -167,7 +169,7 @@ namespace ts.projectSystem { session.executeCommand(addFile2ImportRequest); // Change the content of file1 to `export var T2: string;export var T: number;export function Foo() { };` - const changeModuleFile1ShapeRequest2 = makeSessionRequest(server.CommandNames.Change, { + const changeModuleFile1ShapeRequest2 = makeSessionRequest(CommandNames.Change, { file: moduleFile1.path, line: 1, offset: 1, @@ -272,7 +274,7 @@ namespace ts.projectSystem { const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false); openFilesForSession([globalFile3], session); - const changeGlobalFile3ShapeRequest = makeSessionRequest(server.CommandNames.Change, { + const changeGlobalFile3ShapeRequest = makeSessionRequest(CommandNames.Change, { file: globalFile3.path, line: 1, offset: 1, @@ -283,7 +285,7 @@ namespace ts.projectSystem { // check after file1 shape changes session.executeCommand(changeGlobalFile3ShapeRequest); - const globalFile3FileListRequest = makeSessionRequest(server.CommandNames.CompileOnSaveAffectedFileList, { file: globalFile3.path }); + const globalFile3FileListRequest = makeSessionRequest(CommandNames.CompileOnSaveAffectedFileList, { file: globalFile3.path }); sendAffectedFileRequestAndCheckResult(session, globalFile3FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer2, globalFile3, moduleFile2] }]); }); @@ -316,7 +318,7 @@ namespace ts.projectSystem { const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false); openFilesForSession([moduleFile1], session); - const file1ChangeShapeRequest = makeSessionRequest(server.CommandNames.Change, { + const file1ChangeShapeRequest = makeSessionRequest(CommandNames.Change, { file: moduleFile1.path, line: 1, offset: 27, @@ -345,7 +347,7 @@ namespace ts.projectSystem { const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false); openFilesForSession([moduleFile1], session); - const file1ChangeShapeRequest = makeSessionRequest(server.CommandNames.Change, { + const file1ChangeShapeRequest = makeSessionRequest(CommandNames.Change, { file: moduleFile1.path, line: 1, offset: 27, @@ -369,7 +371,7 @@ namespace ts.projectSystem { openFilesForSession([moduleFile1, file1Consumer1], session); sendAffectedFileRequestAndCheckResult(session, moduleFile1FileListRequest, [{ projectFileName: configFile.path, files: [moduleFile1, file1Consumer1, file1Consumer1Consumer1] }]); - const changeFile1Consumer1ShapeRequest = makeSessionRequest(server.CommandNames.Change, { + const changeFile1Consumer1ShapeRequest = makeSessionRequest(CommandNames.Change, { file: file1Consumer1.path, line: 2, offset: 1, @@ -400,7 +402,7 @@ namespace ts.projectSystem { const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false); openFilesForSession([file1, file2], session); - const file1AffectedListRequest = makeSessionRequest(server.CommandNames.CompileOnSaveAffectedFileList, { file: file1.path }); + const file1AffectedListRequest = makeSessionRequest(CommandNames.CompileOnSaveAffectedFileList, { file: file1.path }); sendAffectedFileRequestAndCheckResult(session, file1AffectedListRequest, [{ projectFileName: configFile.path, files: [file1, file2] }]); }); @@ -415,7 +417,7 @@ namespace ts.projectSystem { const session = createSession(host); openFilesForSession([file1, file2, file3], session); - const file1AffectedListRequest = makeSessionRequest(server.CommandNames.CompileOnSaveAffectedFileList, { file: file1.path }); + const file1AffectedListRequest = makeSessionRequest(CommandNames.CompileOnSaveAffectedFileList, { file: file1.path }); sendAffectedFileRequestAndCheckResult(session, file1AffectedListRequest, [ { projectFileName: configFile1.path, files: [file1, file2] }, @@ -437,11 +439,11 @@ namespace ts.projectSystem { host.reloadFS([referenceFile1, configFile]); host.triggerFileWatcherCallback(moduleFile1.path, /*removed*/ true); - const request = makeSessionRequest(server.CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path }); + const request = makeSessionRequest(CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path }); sendAffectedFileRequestAndCheckResult(session, request, [ { projectFileName: configFile.path, files: [referenceFile1] } ]); - const requestForMissingFile = makeSessionRequest(server.CommandNames.CompileOnSaveAffectedFileList, { file: moduleFile1.path }); + const requestForMissingFile = makeSessionRequest(CommandNames.CompileOnSaveAffectedFileList, { file: moduleFile1.path }); sendAffectedFileRequestAndCheckResult(session, requestForMissingFile, []); }); @@ -456,7 +458,7 @@ namespace ts.projectSystem { const session = createSession(host); openFilesForSession([referenceFile1], session); - const request = makeSessionRequest(server.CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path }); + const request = makeSessionRequest(CommandNames.CompileOnSaveAffectedFileList, { file: referenceFile1.path }); sendAffectedFileRequestAndCheckResult(session, request, [ { projectFileName: configFile.path, files: [referenceFile1] } ]); @@ -483,7 +485,7 @@ namespace ts.projectSystem { const session = new server.Session(host, nullCancellationToken, /*useSingleInferredProject*/ false, typingsInstaller, Utils.byteLength, process.hrtime, nullLogger, /*canUseEvents*/ false); openFilesForSession([file1, file2], session); - const compileFileRequest = makeSessionRequest(server.CommandNames.CompileOnSaveEmitFile, { file: file1.path, projectFileName: configFile.path }); + const compileFileRequest = makeSessionRequest(CommandNames.CompileOnSaveEmitFile, { file: file1.path, projectFileName: configFile.path }); session.executeCommand(compileFileRequest); const expectedEmittedFileName = "/a/b/f1.js"; diff --git a/src/harness/unittests/convertCompilerOptionsFromJson.ts b/src/harness/unittests/convertCompilerOptionsFromJson.ts index ba25409a9b4..33cad7130c7 100644 --- a/src/harness/unittests/convertCompilerOptionsFromJson.ts +++ b/src/harness/unittests/convertCompilerOptionsFromJson.ts @@ -405,6 +405,7 @@ namespace ts { allowJs: true, maxNodeModuleJsDepth: 2, allowSyntheticDefaultImports: true, + skipLibCheck: true, module: ModuleKind.CommonJS, target: ScriptTarget.ES5, noImplicitAny: false, @@ -433,6 +434,7 @@ namespace ts { allowJs: false, maxNodeModuleJsDepth: 2, allowSyntheticDefaultImports: true, + skipLibCheck: true, module: ModuleKind.CommonJS, target: ScriptTarget.ES5, noImplicitAny: false, @@ -456,7 +458,8 @@ namespace ts { { allowJs: true, maxNodeModuleJsDepth: 2, - allowSyntheticDefaultImports: true + allowSyntheticDefaultImports: true, + skipLibCheck: true }, errors: [{ file: undefined, @@ -477,7 +480,8 @@ namespace ts { { allowJs: true, maxNodeModuleJsDepth: 2, - allowSyntheticDefaultImports: true + allowSyntheticDefaultImports: true, + skipLibCheck: true }, errors: [] } diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index b758761ee76..dc4cdd08520 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -3,6 +3,8 @@ namespace ts.projectSystem { import TI = server.typingsInstaller; + import protocol = server.protocol; + import CommandNames = server.CommandNames; const safeList = { path: "/safeList.json", @@ -128,7 +130,7 @@ namespace ts.projectSystem { return combinePaths(getDirectoryPath(libFile.path), "tsc.js"); } - export function toExternalFile(fileName: string): server.protocol.ExternalFile { + export function toExternalFile(fileName: string): protocol.ExternalFile { return { fileName }; } @@ -527,7 +529,7 @@ namespace ts.projectSystem { } export function makeSessionRequest(command: string, args: T) { - const newRequest: server.protocol.Request = { + const newRequest: protocol.Request = { seq: 0, type: "request", command, @@ -538,7 +540,7 @@ namespace ts.projectSystem { export function openFilesForSession(files: FileOrFolder[], session: server.Session) { for (const file of files) { - const request = makeSessionRequest(server.CommandNames.Open, { file: file.path }); + const request = makeSessionRequest(CommandNames.Open, { file: file.path }); session.executeCommand(request); } } @@ -1751,7 +1753,7 @@ namespace ts.projectSystem { }); describe("navigate-to for javascript project", () => { - function containsNavToItem(items: server.protocol.NavtoItem[], itemName: string, itemKind: string) { + function containsNavToItem(items: protocol.NavtoItem[], itemName: string, itemKind: string) { return find(items, item => item.name === itemName && item.kind === itemKind) !== undefined; } @@ -1769,12 +1771,12 @@ namespace ts.projectSystem { openFilesForSession([file1], session); // Try to find some interface type defined in lib.d.ts - const libTypeNavToRequest = makeSessionRequest(server.CommandNames.Navto, { searchValue: "Document", file: file1.path, projectFileName: configFile.path }); - const items: server.protocol.NavtoItem[] = session.executeCommand(libTypeNavToRequest).response; + const libTypeNavToRequest = makeSessionRequest(CommandNames.Navto, { searchValue: "Document", file: file1.path, projectFileName: configFile.path }); + const items: protocol.NavtoItem[] = session.executeCommand(libTypeNavToRequest).response; assert.isFalse(containsNavToItem(items, "Document", "interface"), `Found lib.d.ts symbol in JavaScript project nav to request result.`); - const localFunctionNavToRequst = makeSessionRequest(server.CommandNames.Navto, { searchValue: "foo", file: file1.path, projectFileName: configFile.path }); - const items2: server.protocol.NavtoItem[] = session.executeCommand(localFunctionNavToRequst).response; + const localFunctionNavToRequst = makeSessionRequest(CommandNames.Navto, { searchValue: "foo", file: file1.path, projectFileName: configFile.path }); + const items2: protocol.NavtoItem[] = session.executeCommand(localFunctionNavToRequst).response; assert.isTrue(containsNavToItem(items2, "foo", "function"), `Cannot find function symbol "foo".`); }); }); @@ -2309,4 +2311,109 @@ namespace ts.projectSystem { serverEventManager.checkEventCountOfType("configFileDiag", 1); }); }); + + describe("skipLibCheck", () => { + it("should be turned on for js-only inferred projects", () => { + const file1 = { + path: "/a/b/file1.js", + content: ` + /// + var x = 1;` + }; + const file2 = { + path: "/a/b/file2.d.ts", + content: ` + interface T { + name: string; + }; + interface T { + name: number; + };` + }; + const host = createServerHost([file1, file2]); + const session = createSession(host); + openFilesForSession([file1, file2], session); + + const file2GetErrRequest = makeSessionRequest( + CommandNames.SemanticDiagnosticsSync, + { file: file2.path } + ); + let errorResult = session.executeCommand(file2GetErrRequest).response; + assert.isTrue(errorResult.length === 0); + + const closeFileRequest = makeSessionRequest(CommandNames.Close, { file: file1.path }); + session.executeCommand(closeFileRequest); + errorResult = session.executeCommand(file2GetErrRequest).response; + assert.isTrue(errorResult.length !== 0); + + openFilesForSession([file1], session); + errorResult = session.executeCommand(file2GetErrRequest).response; + assert.isTrue(errorResult.length === 0); + }); + + it("should be turned on for js-only external projects", () => { + const jsFile = { + path: "/a/b/file1.js", + content: "let x =1;" + }; + const dTsFile = { + path: "/a/b/file2.d.ts", + content: ` + interface T { + name: string; + }; + interface T { + name: number; + };` + }; + const host = createServerHost([jsFile, dTsFile]); + const session = createSession(host); + + const openExternalProjectRequest = makeSessionRequest( + CommandNames.OpenExternalProject, + { + projectFileName: "project1", + rootFiles: toExternalFiles([jsFile.path, dTsFile.path]), + options: {} + } + ); + session.executeCommand(openExternalProjectRequest); + + const dTsFileGetErrRequest = makeSessionRequest( + CommandNames.SemanticDiagnosticsSync, + { file: dTsFile.path } + ); + const errorResult = session.executeCommand(dTsFileGetErrRequest).response; + assert.isTrue(errorResult.length === 0); + }); + }); + + describe("non-existing directories listed in config file input array", () => { + it("should be tolerated without crashing the server", () => { + const configFile = { + path: "/a/b/tsconfig.json", + content: `{ + "compilerOptions": {}, + "include": ["app/*", "test/**/*", "something"] + }` + }; + const file1 = { + path: "/a/b/file1.ts", + content: "let t = 10;" + }; + + const host = createServerHost([file1, configFile]); + const projectService = createProjectService(host); + projectService.openClientFile(file1.path); + host.runQueuedTimeoutCallbacks(); + checkNumberOfConfiguredProjects(projectService, 1); + checkNumberOfInferredProjects(projectService, 1); + + const configuredProject = projectService.configuredProjects[0]; + assert.isTrue(configuredProject.getFileNames().length == 0); + + const inferredProject = projectService.inferredProjects[0]; + assert.isTrue(inferredProject.containsFile(file1.path)); + }); + }); } \ No newline at end of file diff --git a/src/lib/es2015.core.d.ts b/src/lib/es2015.core.d.ts index 5d570bb0866..356512ecf58 100644 --- a/src/lib/es2015.core.d.ts +++ b/src/lib/es2015.core.d.ts @@ -201,7 +201,7 @@ interface NumberConstructor { /** * Returns true if passed value is finite. - * Unlike the global isFininte, Number.isFinite doesn't forcibly convert the parameter to a + * Unlike the global isFinite, Number.isFinite doesn't forcibly convert the parameter to a * number. Only finite values of the type number, result in true. * @param number A numeric value. */ 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/client.ts b/src/server/client.ts index 2acc0a58cad..b0bc2c5dac0 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -1,7 +1,6 @@ /// namespace ts.server { - export interface SessionClientHost extends LanguageServiceHost { writeMessage(message: string): void; } @@ -512,7 +511,7 @@ namespace ts.server { return this.lastRenameEntry.locations; } - decodeNavigationBarItems(items: protocol.NavigationBarItem[], fileName: string, lineMap: number[]): NavigationBarItem[] { + private decodeNavigationBarItems(items: protocol.NavigationBarItem[], fileName: string, lineMap: number[]): NavigationBarItem[] { if (!items) { return []; } @@ -521,10 +520,7 @@ namespace ts.server { text: item.text, kind: item.kind, kindModifiers: item.kindModifiers || "", - spans: item.spans.map(span => - createTextSpanFromBounds( - this.lineOffsetToPosition(fileName, span.start, lineMap), - this.lineOffsetToPosition(fileName, span.end, lineMap))), + spans: item.spans.map(span => this.decodeSpan(span, fileName, lineMap)), childItems: this.decodeNavigationBarItems(item.childItems, fileName, lineMap), indent: item.indent, bolded: false, @@ -533,17 +529,37 @@ namespace ts.server { } getNavigationBarItems(fileName: string): NavigationBarItem[] { - const args: protocol.FileRequestArgs = { - file: fileName - }; - - const request = this.processRequest(CommandNames.NavBar, args); + const request = this.processRequest(CommandNames.NavBar, { file: fileName }); const response = this.processResponse(request); const lineMap = this.getLineMap(fileName); return this.decodeNavigationBarItems(response.body, fileName, lineMap); } + private decodeNavigationTree(tree: protocol.NavigationTree, fileName: string, lineMap: number[]): NavigationTree { + return { + text: tree.text, + kind: tree.kind, + kindModifiers: tree.kindModifiers, + spans: tree.spans.map(span => this.decodeSpan(span, fileName, lineMap)), + childItems: map(tree.childItems, item => this.decodeNavigationTree(item, fileName, lineMap)) + }; + } + + getNavigationTree(fileName: string): NavigationTree { + const request = this.processRequest(CommandNames.NavTree, { file: fileName }); + const response = this.processResponse(request); + + const lineMap = this.getLineMap(fileName); + return this.decodeNavigationTree(response.body, fileName, lineMap); + } + + private decodeSpan(span: protocol.TextSpan, fileName: string, lineMap: number[]) { + return createTextSpanFromBounds( + this.lineOffsetToPosition(fileName, span.start, lineMap), + this.lineOffsetToPosition(fileName, span.end, lineMap)); + } + getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TextSpan { throw new Error("Not Implemented Yet."); } diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts index dc2c45156cd..91b9f90c88b 100644 --- a/src/server/editorServices.ts +++ b/src/server/editorServices.ts @@ -1,6 +1,5 @@ /// /// -/// /// /// /// @@ -711,7 +710,7 @@ namespace ts.server { Debug.assert(!!parsedCommandLine.fileNames); if (parsedCommandLine.fileNames.length === 0) { - errors.push(createCompilerDiagnostic(Diagnostics.The_config_file_0_found_doesn_t_contain_any_source_files, configFilename)); + (errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.The_config_file_0_found_doesn_t_contain_any_source_files, configFilename)); return { success: false, configFileErrors: errors }; } diff --git a/src/server/project.ts b/src/server/project.ts index b59efb03cfd..a355d75f942 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -20,16 +20,42 @@ namespace ts.server { } } - function isJsOrDtsFile(info: ScriptInfo) { - return info.scriptKind === ScriptKind.JS || info.scriptKind == ScriptKind.JSX || fileExtensionIs(info.fileName, ".d.ts"); + function countEachFileTypes(infos: ScriptInfo[]): { js: number, jsx: number, ts: number, tsx: number, dts: number } { + const result = { js: 0, jsx: 0, ts: 0, tsx: 0, dts: 0 }; + for (const info of infos) { + switch (info.scriptKind) { + case ScriptKind.JS: + result.js += 1; + break; + case ScriptKind.JSX: + result.jsx += 1; + break; + case ScriptKind.TS: + fileExtensionIs(info.fileName, ".d.ts") + ? result.dts += 1 + : result.ts += 1; + break; + case ScriptKind.TSX: + result.tsx += 1; + break; + } + } + return result; + } + + function hasOneOrMoreJsAndNoTsFiles(project: Project) { + const counts = countEachFileTypes(project.getScriptInfos()); + return counts.js > 0 && counts.ts === 0 && counts.tsx === 0; } export function allRootFilesAreJsOrDts(project: Project): boolean { - return project.getRootScriptInfos().every(isJsOrDtsFile); + const counts = countEachFileTypes(project.getRootScriptInfos()); + return counts.ts === 0 && counts.tsx === 0; } export function allFilesAreJsOrDts(project: Project): boolean { - return project.getScriptInfos().every(isJsOrDtsFile); + const counts = countEachFileTypes(project.getScriptInfos()); + return counts.ts === 0 && counts.tsx === 0; } export interface ProjectFilesWithTSDiagnostics extends protocol.ProjectFiles { @@ -71,11 +97,16 @@ namespace ts.server { public typesVersion = 0; - public isJsOnlyProject() { + public isNonTsProject() { this.updateGraph(); return allFilesAreJsOrDts(this); } + public isJsOnlyProject() { + this.updateGraph(); + return hasOneOrMoreJsAndNoTsFiles(this); + } + constructor( readonly projectKind: ProjectKind, readonly projectService: ProjectService, diff --git a/src/server/protocol.d.ts b/src/server/protocol.ts similarity index 79% rename from src/server/protocol.d.ts rename to src/server/protocol.ts index 0ae54b8e0cf..80623f05aec 100644 --- a/src/server/protocol.d.ts +++ b/src/server/protocol.ts @@ -1,7 +1,102 @@ /** * Declaration module describing the TypeScript Server protocol */ -declare namespace ts.server.protocol { +namespace ts.server.protocol { + export namespace CommandTypes { + export type Brace = "brace"; + /* @internal */ + export type BraceFull = "brace-full"; + export type BraceCompletion = "braceCompletion"; + export type Change = "change"; + export type Close = "close"; + export type Completions = "completions"; + /* @internal */ + export type CompletionsFull = "completions-full"; + export type CompletionDetails = "completionEntryDetails"; + export type CompileOnSaveAffectedFileList = "compileOnSaveAffectedFileList"; + export type CompileOnSaveEmitFile = "compileOnSaveEmitFile"; + export type Configure = "configure"; + export type Definition = "definition"; + /* @internal */ + export type DefinitionFull = "definition-full"; + export type Implementation = "implementation"; + /* @internal */ + export type ImplementationFull = "implementation-full"; + export type Exit = "exit"; + export type Format = "format"; + export type Formatonkey = "formatonkey"; + /* @internal */ + export type FormatFull = "format-full"; + /* @internal */ + export type FormatonkeyFull = "formatonkey-full"; + /* @internal */ + export type FormatRangeFull = "formatRange-full"; + export type Geterr = "geterr"; + export type GeterrForProject = "geterrForProject"; + export type SemanticDiagnosticsSync = "semanticDiagnosticsSync"; + export type SyntacticDiagnosticsSync = "syntacticDiagnosticsSync"; + export type NavBar = "navbar"; + /* @internal */ + export type NavBarFull = "navbar-full"; + export type Navto = "navto"; + /* @internal */ + export type NavtoFull = "navto-full"; + export type NavTree = "navtree"; + export type NavTreeFull = "navtree-full"; + export type Occurrences = "occurrences"; + export type DocumentHighlights = "documentHighlights"; + /* @internal */ + export type DocumentHighlightsFull = "documentHighlights-full"; + export type Open = "open"; + export type Quickinfo = "quickinfo"; + /* @internal */ + export type QuickinfoFull = "quickinfo-full"; + export type References = "references"; + /* @internal */ + export type ReferencesFull = "references-full"; + export type Reload = "reload"; + export type Rename = "rename"; + /* @internal */ + export type RenameInfoFull = "rename-full"; + /* @internal */ + export type RenameLocationsFull = "renameLocations-full"; + export type Saveto = "saveto"; + export type SignatureHelp = "signatureHelp"; + /* @internal */ + export type SignatureHelpFull = "signatureHelp-full"; + export type TypeDefinition = "typeDefinition"; + export type ProjectInfo = "projectInfo"; + export type ReloadProjects = "reloadProjects"; + export type Unknown = "unknown"; + export type OpenExternalProject = "openExternalProject"; + export type OpenExternalProjects = "openExternalProjects"; + export type CloseExternalProject = "closeExternalProject"; + /* @internal */ + export type SynchronizeProjectList = "synchronizeProjectList"; + /* @internal */ + export type ApplyChangedToOpenFiles = "applyChangedToOpenFiles"; + /* @internal */ + export type EncodedSemanticClassificationsFull = "encodedSemanticClassifications-full"; + /* @internal */ + export type Cleanup = "cleanup"; + /* @internal */ + export type OutliningSpans = "outliningSpans"; + export type TodoComments = "todoComments"; + export type Indentation = "indentation"; + export type DocCommentTemplate = "docCommentTemplate"; + /* @internal */ + export type CompilerOptionsDiagnosticsFull = "compilerOptionsDiagnostics-full"; + /* @internal */ + export type NameOrDottedNameSpan = "nameOrDottedNameSpan"; + /* @internal */ + export type BreakpointStatement = "breakpointStatement"; + export type CompilerOptionsForInferredProjects = "compilerOptionsForInferredProjects"; + export type GetCodeFixes = "getCodeFixes"; + /* @internal */ + export type GetCodeFixesFull = "getCodeFixes-full"; + export type GetSupportedCodeFixes = "getSupportedCodeFixes"; + } + /** * A TypeScript Server message */ @@ -36,6 +131,7 @@ declare namespace ts.server.protocol { * Request to reload the project structure for all the opened files */ export interface ReloadProjectsRequest extends Message { + command: CommandTypes.ReloadProjects; } /** @@ -98,10 +194,25 @@ declare namespace ts.server.protocol { projectFileName?: string; } + /** + * Requests a JS Doc comment template for a given position + */ + export interface DocCommentTemplateRequest extends FileLocationRequest { + command: CommandTypes.DocCommentTemplate; + } + + /** + * Response to DocCommentTemplateRequest + */ + export interface DocCommandTemplateResponse extends Response { + body?: TextInsertion; + } + /** * A request to get TODO comments from the file */ export interface TodoCommentRequest extends FileRequest { + command: CommandTypes.TodoComments; arguments: TodoCommentRequestArgs; } @@ -110,18 +221,63 @@ declare namespace ts.server.protocol { */ export interface TodoCommentRequestArgs extends FileRequestArgs { /** - * Array of target TodoCommentDescriptors that describes TODO comments to be found + * Array of target TodoCommentDescriptors that describes TODO comments to be found */ descriptors: TodoCommentDescriptor[]; } + /** + * Response for TodoCommentRequest request. + */ + export interface TodoCommentsResponse extends Response { + body?: TodoComment[]; + } + + /** + * Request to obtain outlining spans in file. + */ + /* @internal */ + export interface OutliningSpansRequest extends FileRequest { + command: CommandTypes.OutliningSpans; + } + + /** + * Response to OutliningSpansRequest request. + */ + /* @internal */ + export interface OutliningSpansResponse extends Response { + body?: OutliningSpan[]; + } + /** * A request to get indentation for a location in file */ export interface IndentationRequest extends FileLocationRequest { + command: CommandTypes.Indentation; arguments: IndentationRequestArgs; } + /** + * Response for IndentationRequest request. + */ + export interface IndentationResponse extends Response { + body?: IndentationResult; + } + + /** + * Indentation result representing where indentation should be placed + */ + export interface IndentationResult { + /** + * The base position in the document that the indent should be relative to + */ + position: number; + /** + * The number of columns the indent should be at relative to the position's column. + */ + indentation: number; + } + /** * Arguments for IndentationRequest request. */ @@ -147,6 +303,7 @@ declare namespace ts.server.protocol { * A request to get the project information of the current file. */ export interface ProjectInfoRequest extends Request { + command: CommandTypes.ProjectInfo; arguments: ProjectInfoRequestArgs; } @@ -223,16 +380,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) + * Position (can be specified instead of line/offset pair) */ + /* @internal */ position?: number; } @@ -240,6 +398,7 @@ declare namespace ts.server.protocol { * Request for the available codefixes at a specific position. */ export interface CodeFixRequest extends Request { + command: CommandTypes.GetCodeFixes; arguments: CodeFixRequestArgs; } @@ -250,31 +409,33 @@ declare namespace ts.server.protocol { /** * The line number for the request (1-based). */ - startLine?: number; + startLine: number; /** * The character offset (on the line) for the request (1-based). */ - startOffset?: number; + startOffset: number; /** * Position (can be specified instead of line/offset pair) */ + /* @internal */ startPosition?: number; /** * The line number for the request (1-based). */ - endLine?: number; + endLine: number; /** * The character offset (on the line) for the request (1-based). */ - endOffset?: number; + endOffset: number; /** * Position (can be specified instead of line/offset pair) */ + /* @internal */ endPosition?: number; /** @@ -283,6 +444,13 @@ declare namespace ts.server.protocol { errorCodes?: number[]; } + /** + * Response for GetCodeFixes request. + */ + export interface GetCodeFixesResponse extends Response { + body?: CodeAction[]; + } + /** * A request whose arguments specify a file location (file, line, col). */ @@ -291,16 +459,34 @@ declare namespace ts.server.protocol { } /** - * A request to get semantic diagnostics for a span in the file + * A request to get codes of supported code fixes. */ - export interface SemanticDiagnosticsRequest extends FileRequest { - arguments: SemanticDiagnosticsRequestArgs; + export interface GetSupportedCodeFixesRequest extends Request { + command: CommandTypes.GetSupportedCodeFixes; } /** - * Arguments for SemanticDiagnosticsRequest request. + * A response for GetSupportedCodeFixesRequest request. */ - export interface SemanticDiagnosticsRequestArgs extends FileRequestArgs { + export interface GetSupportedCodeFixesResponse extends Response { + /** + * List of error codes supported by the server. + */ + body?: string[]; + } + + /** + * A request to get encoded semantic classifications for a span in the file + */ + /** @internal */ + export interface EncodedSemanticClassificationsRequest extends FileRequest { + arguments: EncodedSemanticClassificationsRequestArgs; + } + + /** + * Arguments for EncodedSemanticClassificationsRequest request. + */ + export interface EncodedSemanticClassificationsRequestArgs extends FileRequestArgs { /** * Start position of the span. */ @@ -328,6 +514,7 @@ declare namespace ts.server.protocol { * define the symbol found in file at location line, col. */ export interface DefinitionRequest extends FileLocationRequest { + command: CommandTypes.Definition; } /** @@ -336,6 +523,7 @@ declare namespace ts.server.protocol { * define the type for the symbol found in file at location line, col. */ export interface TypeDefinitionRequest extends FileLocationRequest { + command: CommandTypes.TypeDefinition; } /** @@ -344,6 +532,7 @@ declare namespace ts.server.protocol { * implement the symbol found in file at location line, col. */ export interface ImplementationRequest extends FileLocationRequest { + command: CommandTypes.Implementation; } /** @@ -404,6 +593,7 @@ declare namespace ts.server.protocol { * Request to get brace completion for a location in the file. */ export interface BraceCompletionRequest extends FileLocationRequest { + command: CommandTypes.BraceCompletion; arguments: BraceCompletionRequestArgs; } @@ -423,6 +613,7 @@ declare namespace ts.server.protocol { * in the file at a given line and column. */ export interface OccurrencesRequest extends FileLocationRequest { + command: CommandTypes.Occurrences; } export interface OccurrencesResponseItem extends FileSpan { @@ -442,6 +633,7 @@ declare namespace ts.server.protocol { * in the file at a given line and column. */ export interface DocumentHighlightsRequest extends FileLocationRequest { + command: CommandTypes.DocumentHighlights; arguments: DocumentHighlightsRequestArgs; } @@ -481,6 +673,7 @@ declare namespace ts.server.protocol { * reference the symbol found in file at location line, col. */ export interface ReferencesRequest extends FileLocationRequest { + command: CommandTypes.References; } export interface ReferencesResponseItem extends FileSpan { @@ -555,6 +748,7 @@ declare namespace ts.server.protocol { * name of the symbol so that client can print it unambiguously. */ export interface RenameRequest extends FileLocationRequest { + command: CommandTypes.Rename; arguments: RenameRequestArgs; } @@ -624,12 +818,12 @@ declare namespace ts.server.protocol { /** * Represents a file in external project. - * External project is project whose set of files, compilation options and open\close state + * External project is project whose set of files, compilation options and open\close state * is maintained by the client (i.e. if all this data come from .csproj file in Visual Studio). * External project will exist even if all files in it are closed and should be closed explicity. - * If external project includes one or more tsconfig.json/jsconfig.json files then tsserver will + * If external project includes one or more tsconfig.json/jsconfig.json files then tsserver will * create configured project for every config file but will maintain a link that these projects were created - * as a result of opening external project so they should be removed once external project is closed. + * as a result of opening external project so they should be removed once external project is closed. */ export interface ExternalFile { /** @@ -754,6 +948,7 @@ declare namespace ts.server.protocol { /** * Represents set of changes in open file */ + /* @internal */ export interface ChangedOpenFile { /** * Name of file @@ -765,65 +960,6 @@ declare namespace ts.server.protocol { 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. @@ -844,12 +980,7 @@ declare namespace ts.server.protocol { /** * The format options to use during formatting and other code editing features. */ - formatOptions?: FormatOptions; - - /** - * If set to true - then all loose files will land into one inferred project - */ - useOneInferredProject?: boolean; + formatOptions?: FormatCodeSettings; } /** @@ -857,6 +988,7 @@ declare namespace ts.server.protocol { * host information, such as host type, tab size, and indent size. */ export interface ConfigureRequest extends Request { + command: CommandTypes.Configure; arguments: ConfigureRequestArguments; } @@ -892,6 +1024,7 @@ declare namespace ts.server.protocol { * send a response to an open request. */ export interface OpenRequest extends Request { + command: CommandTypes.Open; arguments: OpenRequestArgs; } @@ -899,18 +1032,20 @@ declare namespace ts.server.protocol { * Request to open or update external project */ export interface OpenExternalProjectRequest extends Request { + command: CommandTypes.OpenExternalProject; arguments: OpenExternalProjectArgs; } /** * Arguments to OpenExternalProjectRequest request */ - type OpenExternalProjectArgs = ExternalProject; + export type OpenExternalProjectArgs = ExternalProject; /** * Request to open multiple external projects */ export interface OpenExternalProjectsRequest extends Request { + command: CommandTypes.OpenExternalProjects; arguments: OpenExternalProjectsArgs; } @@ -924,10 +1059,25 @@ declare namespace ts.server.protocol { projects: ExternalProject[]; } + /** + * Response to OpenExternalProjectRequest request. This is just an acknowledgement, so + * no body field is required. + */ + export interface OpenExternalProjectResponse extends Response { + } + + /** + * Response to OpenExternalProjectsRequest request. This is just an acknowledgement, so + * no body field is required. + */ + export interface OpenExternalProjectsResponse extends Response { + } + /** * Request to close external project. */ export interface CloseExternalProjectRequest extends Request { + command: CommandTypes.CloseExternalProject; arguments: CloseExternalProjectRequestArgs; } @@ -941,9 +1091,17 @@ declare namespace ts.server.protocol { projectFileName: string; } + /** + * Response to CloseExternalProjectRequest request. This is just an acknowledgement, so + * no body field is required. + */ + export interface CloseExternalProjectResponse extends Response { + } + /** * Request to check if given list of projects is up-to-date and synchronize them if necessary */ + /* @internal */ export interface SynchronizeProjectListRequest extends Request { arguments: SynchronizeProjectListRequestArgs; } @@ -961,6 +1119,7 @@ declare namespace ts.server.protocol { /** * Request to synchronize list of open files with the client */ + /* @internal */ export interface ApplyChangedToOpenFilesRequest extends Request { arguments: ApplyChangedToOpenFilesRequestArgs; } @@ -968,6 +1127,7 @@ declare namespace ts.server.protocol { /** * Arguments to ApplyChangedToOpenFilesRequest */ + /* @internal */ export interface ApplyChangedToOpenFilesRequestArgs { /** * List of newly open files @@ -993,6 +1153,7 @@ declare namespace ts.server.protocol { * or all open loose files and its transitive closure of referenced files if 'useOneInferredProject' is true. */ export interface SetCompilerOptionsForInferredProjectsRequest extends Request { + command: CommandTypes.CompilerOptionsForInferredProjects; arguments: SetCompilerOptionsForInferredProjectsArgs; } @@ -1006,11 +1167,19 @@ declare namespace ts.server.protocol { options: ExternalProjectCompilerOptions; } + /** + * Response to SetCompilerOptionsForInferredProjectsResponse request. This is just an acknowledgement, so + * no body field is required. + */ + export interface SetCompilerOptionsForInferredProjectsResponse extends Response { + } + /** * Exit request; value of command field is "exit". Ask the server process * to exit. */ export interface ExitRequest extends Request { + command: CommandTypes.Exit; } /** @@ -1021,6 +1190,7 @@ declare namespace ts.server.protocol { * currently send a response to a close request. */ export interface CloseRequest extends FileRequest { + command: CommandTypes.Close; } /** @@ -1028,6 +1198,7 @@ declare namespace ts.server.protocol { * NOTE: this us query-only operation and does not generate any output on disk. */ export interface CompileOnSaveAffectedFileListRequest extends FileRequest { + command: CommandTypes.CompileOnSaveAffectedFileList; } /** @@ -1045,7 +1216,7 @@ declare namespace ts.server.protocol { } /** - * Response for CompileOnSaveAffectedFileListRequest request; + * Response for CompileOnSaveAffectedFileListRequest request; */ export interface CompileOnSaveAffectedFileListResponse extends Response { body: CompileOnSaveAffectedFileListSingleProject[]; @@ -1055,7 +1226,8 @@ declare namespace ts.server.protocol { * Request to recompile the file. All generated outputs (.js, .d.ts or .js.map files) is written on disk. */ export interface CompileOnSaveEmitFileRequest extends FileRequest { - args: CompileOnSaveEmitFileRequestArgs; + command: CommandTypes.CompileOnSaveEmitFile; + arguments: CompileOnSaveEmitFileRequestArgs; } /** @@ -1075,6 +1247,7 @@ declare namespace ts.server.protocol { * line, col. */ export interface QuickInfoRequest extends FileLocationRequest { + command: CommandTypes.Quickinfo; } /** @@ -1136,12 +1309,12 @@ declare namespace ts.server.protocol { /** * End position of the range for which to format text in file. */ + /* @internal */ endPosition?: number; - /** * Format options to be used. */ - options?: ts.FormatCodeOptions; + options?: FormatCodeSettings; } /** @@ -1152,6 +1325,7 @@ declare namespace ts.server.protocol { * reformatted text. */ export interface FormatRequest extends FileLocationRequest { + command: CommandTypes.Format; arguments: FormatRequestArgs; } @@ -1213,7 +1387,7 @@ declare namespace ts.server.protocol { */ key: string; - options?: ts.FormatCodeOptions; + options?: FormatCodeSettings; } /** @@ -1225,6 +1399,7 @@ declare namespace ts.server.protocol { * reformatted text. */ export interface FormatOnKeyRequest extends FileLocationRequest { + command: CommandTypes.Formatonkey; arguments: FormatOnKeyRequestArgs; } @@ -1245,6 +1420,7 @@ declare namespace ts.server.protocol { * begin with prefix. */ export interface CompletionsRequest extends FileLocationRequest { + command: CommandTypes.Completions; arguments: CompletionsRequestArgs; } @@ -1265,6 +1441,7 @@ declare namespace ts.server.protocol { * detailed information for each completion entry. */ export interface CompletionDetailsRequest extends FileLocationRequest { + command: CommandTypes.CompletionDetails; arguments: CompletionDetailsRequestArgs; } @@ -1451,6 +1628,7 @@ declare namespace ts.server.protocol { * help. */ export interface SignatureHelpRequest extends FileLocationRequest { + command: CommandTypes.SignatureHelp; arguments: SignatureHelpRequestArgs; } @@ -1465,6 +1643,7 @@ declare namespace ts.server.protocol { * Synchronous request for semantic diagnostics of one file. */ export interface SemanticDiagnosticsSyncRequest extends FileRequest { + command: CommandTypes.SemanticDiagnosticsSync; arguments: SemanticDiagnosticsSyncRequestArgs; } @@ -1483,6 +1662,7 @@ declare namespace ts.server.protocol { * Synchronous request for syntactic diagnostics of one file. */ export interface SyntacticDiagnosticsSyncRequest extends FileRequest { + command: CommandTypes.SyntacticDiagnosticsSync; arguments: SyntacticDiagnosticsSyncRequestArgs; } @@ -1519,6 +1699,7 @@ declare namespace ts.server.protocol { * it request for every file in this project. */ export interface GeterrForProjectRequest extends Request { + command: CommandTypes.GeterrForProject; arguments: GeterrForProjectRequestArgs; } @@ -1550,6 +1731,7 @@ declare namespace ts.server.protocol { * file that is currently visible, in most-recently-used order. */ export interface GeterrRequest extends Request { + command: CommandTypes.Geterr; arguments: GeterrRequestArgs; } @@ -1642,11 +1824,12 @@ declare namespace ts.server.protocol { * The two names can be identical. */ export interface ReloadRequest extends FileRequest { + command: CommandTypes.Reload; arguments: ReloadRequestArgs; } /** - * Response to "reload" request. This is just an acknowledgement, so + * Response to "reload" request. This is just an acknowledgement, so * no body field is required. */ export interface ReloadResponse extends Response { @@ -1671,6 +1854,7 @@ declare namespace ts.server.protocol { * "saveto" request. */ export interface SavetoRequest extends FileRequest { + command: CommandTypes.Saveto; arguments: SavetoRequestArgs; } @@ -1703,6 +1887,7 @@ declare namespace ts.server.protocol { * context for the search is given by the named file. */ export interface NavtoRequest extends FileRequest { + command: CommandTypes.Navto; arguments: NavtoRequestArgs; } @@ -1786,6 +1971,7 @@ declare namespace ts.server.protocol { * Server does not currently send a response to a change request. */ export interface ChangeRequest extends FileLocationRequest { + command: CommandTypes.Change; arguments: ChangeRequestArgs; } @@ -1802,6 +1988,7 @@ declare namespace ts.server.protocol { * found in file at location line, offset. */ export interface BraceRequest extends FileLocationRequest { + command: CommandTypes.Brace; } /** @@ -1810,6 +1997,15 @@ declare namespace ts.server.protocol { * extracted from the requested file. */ export interface NavBarRequest extends FileRequest { + command: CommandTypes.NavBar; + } + + /** + * NavTree request; value of command field is "navtree". + * Return response giving the navigation tree of the requested file. + */ + export interface NavTreeRequest extends FileRequest { + command: CommandTypes.NavTree; } export interface NavigationBarItem { @@ -1844,7 +2040,20 @@ declare namespace ts.server.protocol { indent: number; } + /** protocol.NavigationTree is identical to ts.NavigationTree, except using protocol.TextSpan instead of ts.TextSpan */ + export interface NavigationTree { + text: string; + kind: string; + kindModifiers: string; + spans: TextSpan[]; + childItems?: NavigationTree[]; + } + export interface NavBarResponse extends Response { body?: NavigationBarItem[]; } + + export interface NavTreeResponse extends Response { + body?: NavigationTree; + } } diff --git a/src/server/scriptInfo.ts b/src/server/scriptInfo.ts index 410382a9ca4..68dd59d2d32 100644 --- a/src/server/scriptInfo.ts +++ b/src/server/scriptInfo.ts @@ -4,7 +4,7 @@ namespace ts.server { export class ScriptInfo { /** - * All projects that include this file + * All projects that include this file */ readonly containingProjects: Project[] = []; private formatCodeSettings: ts.FormatCodeSettings; @@ -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 a80b1bea2f3..111ba53a700 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1,6 +1,6 @@ /// /// -/// +/// /// namespace ts.server { @@ -14,6 +14,17 @@ namespace ts.server { return ((1e9 * seconds) + nanoseconds) / 1000000.0; } + function shouldSkipSematicCheck(project: Project) { + if (project.getCompilerOptions().skipLibCheck !== undefined) { + return false; + } + + if ((project.projectKind === ProjectKind.Inferred || project.projectKind === ProjectKind.External) && project.isJsOnlyProject()) { + return true; + } + return false; + } + interface FileStart { file: string; start: ILineInfo; @@ -72,72 +83,74 @@ namespace ts.server { } 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 Implementation = "implementation"; - export const ImplementationFull = "implementation-full"; - 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"; - export const GetCodeFixes = "getCodeFixes"; - export const GetCodeFixesFull = "getCodeFixes-full"; - export const GetSupportedCodeFixes = "getSupportedCodeFixes"; + export const Brace: protocol.CommandTypes.Brace = "brace"; + export const BraceFull: protocol.CommandTypes.BraceFull = "brace-full"; + export const BraceCompletion: protocol.CommandTypes.BraceCompletion = "braceCompletion"; + export const Change: protocol.CommandTypes.Change = "change"; + export const Close: protocol.CommandTypes.Close = "close"; + export const Completions: protocol.CommandTypes.Completions = "completions"; + export const CompletionsFull: protocol.CommandTypes.CompletionsFull = "completions-full"; + export const CompletionDetails: protocol.CommandTypes.CompletionDetails = "completionEntryDetails"; + export const CompileOnSaveAffectedFileList: protocol.CommandTypes.CompileOnSaveAffectedFileList = "compileOnSaveAffectedFileList"; + export const CompileOnSaveEmitFile: protocol.CommandTypes.CompileOnSaveEmitFile = "compileOnSaveEmitFile"; + export const Configure: protocol.CommandTypes.Configure = "configure"; + export const Definition: protocol.CommandTypes.Definition = "definition"; + export const DefinitionFull: protocol.CommandTypes.DefinitionFull = "definition-full"; + export const Exit: protocol.CommandTypes.Exit = "exit"; + export const Format: protocol.CommandTypes.Format = "format"; + export const Formatonkey: protocol.CommandTypes.Formatonkey = "formatonkey"; + export const FormatFull: protocol.CommandTypes.FormatFull = "format-full"; + export const FormatonkeyFull: protocol.CommandTypes.FormatonkeyFull = "formatonkey-full"; + export const FormatRangeFull: protocol.CommandTypes.FormatRangeFull = "formatRange-full"; + export const Geterr: protocol.CommandTypes.Geterr = "geterr"; + export const GeterrForProject: protocol.CommandTypes.GeterrForProject = "geterrForProject"; + export const Implementation: protocol.CommandTypes.Implementation = "implementation"; + export const ImplementationFull: protocol.CommandTypes.ImplementationFull = "implementation-full"; + export const SemanticDiagnosticsSync: protocol.CommandTypes.SemanticDiagnosticsSync = "semanticDiagnosticsSync"; + export const SyntacticDiagnosticsSync: protocol.CommandTypes.SyntacticDiagnosticsSync = "syntacticDiagnosticsSync"; + export const NavBar: protocol.CommandTypes.NavBar = "navbar"; + export const NavBarFull: protocol.CommandTypes.NavBarFull = "navbar-full"; + export const NavTree: protocol.CommandTypes.NavTree = "navtree"; + export const NavTreeFull: protocol.CommandTypes.NavTreeFull = "navtree-full"; + export const Navto: protocol.CommandTypes.Navto = "navto"; + export const NavtoFull: protocol.CommandTypes.NavtoFull = "navto-full"; + export const Occurrences: protocol.CommandTypes.Occurrences = "occurrences"; + export const DocumentHighlights: protocol.CommandTypes.DocumentHighlights = "documentHighlights"; + export const DocumentHighlightsFull: protocol.CommandTypes.DocumentHighlightsFull = "documentHighlights-full"; + export const Open: protocol.CommandTypes.Open = "open"; + export const Quickinfo: protocol.CommandTypes.Quickinfo = "quickinfo"; + export const QuickinfoFull: protocol.CommandTypes.QuickinfoFull = "quickinfo-full"; + export const References: protocol.CommandTypes.References = "references"; + export const ReferencesFull: protocol.CommandTypes.ReferencesFull = "references-full"; + export const Reload: protocol.CommandTypes.Reload = "reload"; + export const Rename: protocol.CommandTypes.Rename = "rename"; + export const RenameInfoFull: protocol.CommandTypes.RenameInfoFull = "rename-full"; + export const RenameLocationsFull: protocol.CommandTypes.RenameLocationsFull = "renameLocations-full"; + export const Saveto: protocol.CommandTypes.Saveto = "saveto"; + export const SignatureHelp: protocol.CommandTypes.SignatureHelp = "signatureHelp"; + export const SignatureHelpFull: protocol.CommandTypes.SignatureHelpFull = "signatureHelp-full"; + export const TypeDefinition: protocol.CommandTypes.TypeDefinition = "typeDefinition"; + export const ProjectInfo: protocol.CommandTypes.ProjectInfo = "projectInfo"; + export const ReloadProjects: protocol.CommandTypes.ReloadProjects = "reloadProjects"; + export const Unknown: protocol.CommandTypes.Unknown = "unknown"; + export const OpenExternalProject: protocol.CommandTypes.OpenExternalProject = "openExternalProject"; + export const OpenExternalProjects: protocol.CommandTypes.OpenExternalProjects = "openExternalProjects"; + export const CloseExternalProject: protocol.CommandTypes.CloseExternalProject = "closeExternalProject"; + export const SynchronizeProjectList: protocol.CommandTypes.SynchronizeProjectList = "synchronizeProjectList"; + export const ApplyChangedToOpenFiles: protocol.CommandTypes.ApplyChangedToOpenFiles = "applyChangedToOpenFiles"; + export const EncodedSemanticClassificationsFull: protocol.CommandTypes.EncodedSemanticClassificationsFull = "encodedSemanticClassifications-full"; + export const Cleanup: protocol.CommandTypes.Cleanup = "cleanup"; + export const OutliningSpans: protocol.CommandTypes.OutliningSpans = "outliningSpans"; + export const TodoComments: protocol.CommandTypes.TodoComments = "todoComments"; + export const Indentation: protocol.CommandTypes.Indentation = "indentation"; + export const DocCommentTemplate: protocol.CommandTypes.DocCommentTemplate = "docCommentTemplate"; + export const CompilerOptionsDiagnosticsFull: protocol.CommandTypes.CompilerOptionsDiagnosticsFull = "compilerOptionsDiagnostics-full"; + export const NameOrDottedNameSpan: protocol.CommandTypes.NameOrDottedNameSpan = "nameOrDottedNameSpan"; + export const BreakpointStatement: protocol.CommandTypes.BreakpointStatement = "breakpointStatement"; + export const CompilerOptionsForInferredProjects: protocol.CommandTypes.CompilerOptionsForInferredProjects = "compilerOptionsForInferredProjects"; + export const GetCodeFixes: protocol.CommandTypes.GetCodeFixes = "getCodeFixes"; + export const GetCodeFixesFull: protocol.CommandTypes.GetCodeFixesFull = "getCodeFixes-full"; + export const GetSupportedCodeFixes: protocol.CommandTypes.GetSupportedCodeFixes = "getSupportedCodeFixes"; } export function formatMessage(msg: T, logger: server.Logger, byteLength: (s: string, encoding: string) => number, newLine: string): string { @@ -259,12 +272,13 @@ namespace ts.server { private semanticCheck(file: NormalizedPath, project: Project) { try { - const diags = project.getLanguageService().getSemanticDiagnostics(file); - - if (diags) { - const bakedDiags = diags.map((diag) => formatDiag(file, project, diag)); - this.event({ file: file, diagnostics: bakedDiags }, "semanticDiag"); + let diags: Diagnostic[] = []; + if (!shouldSkipSematicCheck(project)) { + diags = project.getLanguageService().getSemanticDiagnostics(file); } + + const bakedDiags = diags.map((diag) => formatDiag(file, project, diag)); + this.event({ file: file, diagnostics: bakedDiags }, "semanticDiag"); } catch (err) { this.logError(err, "semantic check"); @@ -349,7 +363,7 @@ namespace ts.server { } } - private getEncodedSemanticClassifications(args: protocol.SemanticDiagnosticsRequestArgs) { + private getEncodedSemanticClassifications(args: protocol.EncodedSemanticClassificationsRequestArgs) { const { file, project } = this.getFileAndProject(args); return project.getLanguageService().getEncodedSemanticClassifications(file, args); } @@ -377,6 +391,9 @@ namespace ts.server { private getDiagnosticsWorker(args: protocol.FileRequestArgs, selector: (project: Project, file: string) => Diagnostic[], includeLinePosition: boolean) { const { project, file } = this.getFileAndProject(args); + if (shouldSkipSematicCheck(project)) { + return []; + } const scriptInfo = project.getScriptInfoForNormalizedPath(file); const diagnostics = selector(project, file); return includeLinePosition @@ -554,7 +571,7 @@ namespace ts.server { const scriptInfo = this.projectService.getScriptInfo(args.file); projects = scriptInfo.containingProjects; } - // ts.filter handles case when 'projects' is undefined + // ts.filter handles case when 'projects' is undefined projects = filter(projects, p => p.languageServiceEnabled); if (!projects || !projects.length) { return Errors.ThrowNoProject(); @@ -945,15 +962,8 @@ namespace ts.server { return completions.entries.reduce((result: protocol.CompletionEntry[], entry: ts.CompletionEntry) => { if (completions.isMemberCompletion || (entry.name.toLowerCase().indexOf(prefix.toLowerCase()) === 0)) { const { name, kind, kindModifiers, sortText, replacementSpan } = entry; - - let convertedSpan: protocol.TextSpan = undefined; - if (replacementSpan) { - convertedSpan = { - start: scriptInfo.positionToLineOffset(replacementSpan.start), - end: scriptInfo.positionToLineOffset(replacementSpan.start + replacementSpan.length) - }; - } - + const convertedSpan: protocol.TextSpan = + replacementSpan ? this.decorateSpan(replacementSpan, scriptInfo) : undefined; result.push({ name, kind, kindModifiers, sortText, replacementSpan: convertedSpan }); } return result; @@ -1091,22 +1101,13 @@ namespace ts.server { this.projectService.closeClientFile(file); } - private decorateNavigationBarItem(project: Project, fileName: NormalizedPath, items: ts.NavigationBarItem[]): protocol.NavigationBarItem[] { - if (!items) { - return undefined; - } - - const scriptInfo = project.getScriptInfoForNormalizedPath(fileName); - - return items.map(item => ({ + private decorateNavigationBarItems(items: ts.NavigationBarItem[], scriptInfo: ScriptInfo): protocol.NavigationBarItem[] { + return map(items, item => ({ text: item.text, kind: item.kind, kindModifiers: item.kindModifiers, - spans: item.spans.map(span => ({ - start: scriptInfo.positionToLineOffset(span.start), - end: scriptInfo.positionToLineOffset(ts.textSpanEnd(span)) - })), - childItems: this.decorateNavigationBarItem(project, fileName, item.childItems), + spans: item.spans.map(span => this.decorateSpan(span, scriptInfo)), + childItems: this.decorateNavigationBarItems(item.childItems, scriptInfo), indent: item.indent })); } @@ -1114,15 +1115,40 @@ namespace ts.server { private getNavigationBarItems(args: protocol.FileRequestArgs, simplifiedResult: boolean): protocol.NavigationBarItem[] | NavigationBarItem[] { const { file, project } = this.getFileAndProject(args); const items = project.getLanguageService(/*ensureSynchronized*/ false).getNavigationBarItems(file); - if (!items) { - return undefined; - } - - return simplifiedResult - ? this.decorateNavigationBarItem(project, file, items) + return !items + ? undefined + : simplifiedResult + ? this.decorateNavigationBarItems(items, project.getScriptInfoForNormalizedPath(file)) : items; } + private decorateNavigationTree(tree: ts.NavigationTree, scriptInfo: ScriptInfo): protocol.NavigationTree { + return { + text: tree.text, + kind: tree.kind, + kindModifiers: tree.kindModifiers, + spans: tree.spans.map(span => this.decorateSpan(span, scriptInfo)), + childItems: map(tree.childItems, item => this.decorateNavigationTree(item, scriptInfo)) + }; + } + + private decorateSpan(span: TextSpan, scriptInfo: ScriptInfo): protocol.TextSpan { + return { + start: scriptInfo.positionToLineOffset(span.start), + end: scriptInfo.positionToLineOffset(ts.textSpanEnd(span)) + }; + } + + private getNavigationTree(args: protocol.FileRequestArgs, simplifiedResult: boolean): protocol.NavigationTree | NavigationTree { + const { file, project } = this.getFileAndProject(args); + const tree = project.getLanguageService(/*ensureSynchronized*/ false).getNavigationTree(file); + return !tree + ? undefined + : simplifiedResult + ? this.decorateNavigationTree(tree, project.getScriptInfoForNormalizedPath(file)) + : tree; + } + private getNavigateToItems(args: protocol.NavtoRequestArgs, simplifiedResult: boolean): protocol.NavtoItem[] | NavigateToItem[] { const projects = this.getProjects(args); @@ -1131,7 +1157,7 @@ namespace ts.server { return combineProjectOutput( projects, project => { - const navItems = project.getLanguageService().getNavigateToItems(args.searchValue, args.maxResultCount, fileName, /*excludeDts*/ project.isJsOnlyProject()); + const navItems = project.getLanguageService().getNavigateToItems(args.searchValue, args.maxResultCount, fileName, /*excludeDts*/ project.isNonTsProject()); if (!navItems) { return []; } @@ -1169,7 +1195,7 @@ namespace ts.server { else { return combineProjectOutput( projects, - project => project.getLanguageService().getNavigateToItems(args.searchValue, args.maxResultCount, fileName, /*excludeDts*/ project.isJsOnlyProject()), + project => project.getLanguageService().getNavigateToItems(args.searchValue, args.maxResultCount, fileName, /*excludeDts*/ project.isNonTsProject()), /*comparer*/ undefined, navigateToItemIsEqualTo); } @@ -1259,19 +1285,11 @@ namespace ts.server { const position = this.getPosition(args, scriptInfo); const spans = project.getLanguageService(/*ensureSynchronized*/ false).getBraceMatchingAtPosition(file, position); - if (!spans) { - return undefined; - } - if (simplifiedResult) { - - return spans.map(span => ({ - start: scriptInfo.positionToLineOffset(span.start), - end: scriptInfo.positionToLineOffset(span.start + span.length) - })); - } - else { - return spans; - } + return !spans + ? undefined + : simplifiedResult + ? spans.map(span => this.decorateSpan(span, scriptInfo)) + : spans; } getDiagnosticsForProject(delay: number, fileName: string) { @@ -1452,7 +1470,7 @@ namespace ts.server { [CommandNames.BraceCompletion]: (request: protocol.BraceCompletionRequest) => { return this.requiredResponse(this.isValidBraceCompletion(request.arguments)); }, - [CommandNames.DocCommentTemplate]: (request: protocol.FileLocationRequest) => { + [CommandNames.DocCommentTemplate]: (request: protocol.DocCommentTemplateRequest) => { return this.requiredResponse(this.getDocCommentTemplate(request.arguments)); }, [CommandNames.Format]: (request: protocol.FormatRequest) => { @@ -1494,7 +1512,7 @@ namespace ts.server { [CommandNames.CompilerOptionsDiagnosticsFull]: (request: protocol.CompilerOptionsDiagnosticsRequest) => { return this.requiredResponse(this.getCompilerOptionsDiagnostics(request.arguments)); }, - [CommandNames.EncodedSemanticClassificationsFull]: (request: protocol.SemanticDiagnosticsRequest) => { + [CommandNames.EncodedSemanticClassificationsFull]: (request: protocol.EncodedSemanticClassificationsRequest) => { return this.requiredResponse(this.getEncodedSemanticClassifications(request.arguments)); }, [CommandNames.Cleanup]: (request: protocol.Request) => { @@ -1556,6 +1574,12 @@ namespace ts.server { [CommandNames.NavBarFull]: (request: protocol.FileRequest) => { return this.requiredResponse(this.getNavigationBarItems(request.arguments, /*simplifiedResult*/ false)); }, + [CommandNames.NavTree]: (request: protocol.FileRequest) => { + return this.requiredResponse(this.getNavigationTree(request.arguments, /*simplifiedResult*/ true)); + }, + [CommandNames.NavTreeFull]: (request: protocol.FileRequest) => { + return this.requiredResponse(this.getNavigationTree(request.arguments, /*simplifiedResult*/ false)); + }, [CommandNames.Occurrences]: (request: protocol.FileLocationRequest) => { return this.requiredResponse(this.getOccurrences(request.arguments)); }, diff --git a/src/server/tsconfig.json b/src/server/tsconfig.json index 7eb8c28f383..9f907446c03 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" ] diff --git a/src/server/utilities.ts b/src/server/utilities.ts index beceab79229..5bd3423e570 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -157,52 +157,53 @@ namespace ts.server { } }; } - function throwLanguageServiceIsDisabledError() { + function throwLanguageServiceIsDisabledError(): never { throw new Error("LanguageService is disabled"); } export const nullLanguageService: LanguageService = { - cleanupSemanticCache: (): any => throwLanguageServiceIsDisabledError(), - getSyntacticDiagnostics: (): any => throwLanguageServiceIsDisabledError(), - getSemanticDiagnostics: (): any => throwLanguageServiceIsDisabledError(), - getCompilerOptionsDiagnostics: (): any => throwLanguageServiceIsDisabledError(), - getSyntacticClassifications: (): any => throwLanguageServiceIsDisabledError(), - getEncodedSyntacticClassifications: (): any => throwLanguageServiceIsDisabledError(), - getSemanticClassifications: (): any => throwLanguageServiceIsDisabledError(), - getEncodedSemanticClassifications: (): any => throwLanguageServiceIsDisabledError(), - getCompletionsAtPosition: (): any => throwLanguageServiceIsDisabledError(), - findReferences: (): any => throwLanguageServiceIsDisabledError(), - getCompletionEntryDetails: (): any => throwLanguageServiceIsDisabledError(), - getQuickInfoAtPosition: (): any => throwLanguageServiceIsDisabledError(), - findRenameLocations: (): any => throwLanguageServiceIsDisabledError(), - getNameOrDottedNameSpan: (): any => throwLanguageServiceIsDisabledError(), - getBreakpointStatementAtPosition: (): any => throwLanguageServiceIsDisabledError(), - getBraceMatchingAtPosition: (): any => throwLanguageServiceIsDisabledError(), - getSignatureHelpItems: (): any => throwLanguageServiceIsDisabledError(), - getDefinitionAtPosition: (): any => throwLanguageServiceIsDisabledError(), - getRenameInfo: (): any => throwLanguageServiceIsDisabledError(), - getTypeDefinitionAtPosition: (): any => throwLanguageServiceIsDisabledError(), - getReferencesAtPosition: (): any => throwLanguageServiceIsDisabledError(), - getDocumentHighlights: (): any => throwLanguageServiceIsDisabledError(), - getOccurrencesAtPosition: (): any => throwLanguageServiceIsDisabledError(), - getNavigateToItems: (): any => throwLanguageServiceIsDisabledError(), - getNavigationBarItems: (): any => throwLanguageServiceIsDisabledError(), - getOutliningSpans: (): any => throwLanguageServiceIsDisabledError(), - getTodoComments: (): any => throwLanguageServiceIsDisabledError(), - getIndentationAtPosition: (): any => throwLanguageServiceIsDisabledError(), - getFormattingEditsForRange: (): any => throwLanguageServiceIsDisabledError(), - getFormattingEditsForDocument: (): any => throwLanguageServiceIsDisabledError(), - getFormattingEditsAfterKeystroke: (): any => throwLanguageServiceIsDisabledError(), - getDocCommentTemplateAtPosition: (): any => throwLanguageServiceIsDisabledError(), - isValidBraceCompletionAtPosition: (): any => throwLanguageServiceIsDisabledError(), - getEmitOutput: (): any => throwLanguageServiceIsDisabledError(), - getProgram: (): any => throwLanguageServiceIsDisabledError(), - getNonBoundSourceFile: (): any => throwLanguageServiceIsDisabledError(), - dispose: (): any => throwLanguageServiceIsDisabledError(), - getCompletionEntrySymbol: (): any => throwLanguageServiceIsDisabledError(), - getImplementationAtPosition: (): any => throwLanguageServiceIsDisabledError(), - getSourceFile: (): any => throwLanguageServiceIsDisabledError(), - getCodeFixesAtPosition: (): any => throwLanguageServiceIsDisabledError() + cleanupSemanticCache: throwLanguageServiceIsDisabledError, + getSyntacticDiagnostics: throwLanguageServiceIsDisabledError, + getSemanticDiagnostics: throwLanguageServiceIsDisabledError, + getCompilerOptionsDiagnostics: throwLanguageServiceIsDisabledError, + getSyntacticClassifications: throwLanguageServiceIsDisabledError, + getEncodedSyntacticClassifications: throwLanguageServiceIsDisabledError, + getSemanticClassifications: throwLanguageServiceIsDisabledError, + getEncodedSemanticClassifications: throwLanguageServiceIsDisabledError, + getCompletionsAtPosition: throwLanguageServiceIsDisabledError, + findReferences: throwLanguageServiceIsDisabledError, + getCompletionEntryDetails: throwLanguageServiceIsDisabledError, + getQuickInfoAtPosition: throwLanguageServiceIsDisabledError, + findRenameLocations: throwLanguageServiceIsDisabledError, + getNameOrDottedNameSpan: throwLanguageServiceIsDisabledError, + getBreakpointStatementAtPosition: throwLanguageServiceIsDisabledError, + getBraceMatchingAtPosition: throwLanguageServiceIsDisabledError, + getSignatureHelpItems: throwLanguageServiceIsDisabledError, + getDefinitionAtPosition: throwLanguageServiceIsDisabledError, + getRenameInfo: throwLanguageServiceIsDisabledError, + getTypeDefinitionAtPosition: throwLanguageServiceIsDisabledError, + getReferencesAtPosition: throwLanguageServiceIsDisabledError, + getDocumentHighlights: throwLanguageServiceIsDisabledError, + getOccurrencesAtPosition: throwLanguageServiceIsDisabledError, + getNavigateToItems: throwLanguageServiceIsDisabledError, + getNavigationBarItems: throwLanguageServiceIsDisabledError, + getNavigationTree: throwLanguageServiceIsDisabledError, + getOutliningSpans: throwLanguageServiceIsDisabledError, + getTodoComments: throwLanguageServiceIsDisabledError, + getIndentationAtPosition: throwLanguageServiceIsDisabledError, + getFormattingEditsForRange: throwLanguageServiceIsDisabledError, + getFormattingEditsForDocument: throwLanguageServiceIsDisabledError, + getFormattingEditsAfterKeystroke: throwLanguageServiceIsDisabledError, + getDocCommentTemplateAtPosition: throwLanguageServiceIsDisabledError, + isValidBraceCompletionAtPosition: throwLanguageServiceIsDisabledError, + getEmitOutput: throwLanguageServiceIsDisabledError, + getProgram: throwLanguageServiceIsDisabledError, + getNonBoundSourceFile: throwLanguageServiceIsDisabledError, + dispose: throwLanguageServiceIsDisabledError, + getCompletionEntrySymbol: throwLanguageServiceIsDisabledError, + getImplementationAtPosition: throwLanguageServiceIsDisabledError, + getSourceFile: throwLanguageServiceIsDisabledError, + getCodeFixesAtPosition: throwLanguageServiceIsDisabledError }; export interface ServerLanguageServiceHost { @@ -249,7 +250,7 @@ namespace ts.server { // another operation was already scheduled for this id - cancel it this.host.clearTimeout(this.pendingTimeouts[operationId]); } - // schedule new operation, pass arguments + // schedule new operation, pass arguments this.pendingTimeouts[operationId] = this.host.setTimeout(ThrottledOperations.run, delay, this, operationId, cb); } diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index 0397ae73229..18881ae7660 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -21,6 +21,13 @@ namespace ts.NavigationBar { return result; } + export function getNavigationTree(sourceFile: SourceFile): NavigationTree { + curSourceFile = sourceFile; + const result = convertToTree(rootNavigationBarNode(sourceFile)); + curSourceFile = undefined; + return result; + } + // Keep sourceFile handy so we don't have to search for it every time we need to call `getText`. let curSourceFile: SourceFile; function nodeText(node: Node): string { @@ -502,6 +509,16 @@ namespace ts.NavigationBar { // NavigationBarItem requires an array, but will not mutate it, so just give it this for performance. const emptyChildItemArray: NavigationBarItem[] = []; + function convertToTree(n: NavigationBarNode): NavigationTree { + return { + text: getItemName(n.node), + kind: getNodeKind(n.node), + kindModifiers: getNodeModifiers(n.node), + spans: getSpans(n), + childItems: map(n.children, convertToTree) + }; + } + function convertToTopLevelItem(n: NavigationBarNode): NavigationBarItem { return { text: getItemName(n.node), @@ -526,16 +543,16 @@ namespace ts.NavigationBar { grayed: false }; } + } - function getSpans(n: NavigationBarNode): TextSpan[] { - const spans = [getNodeSpan(n.node)]; - if (n.additionalNodes) { - for (const node of n.additionalNodes) { - spans.push(getNodeSpan(node)); - } + function getSpans(n: NavigationBarNode): TextSpan[] { + const spans = [getNodeSpan(n.node)]; + if (n.additionalNodes) { + for (const node of n.additionalNodes) { + spans.push(getNodeSpan(node)); } - return spans; } + return spans; } function getModuleName(moduleDeclaration: ModuleDeclaration): string { diff --git a/src/services/services.ts b/src/services/services.ts index cdad39477ce..666644aca1b 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1523,9 +1523,11 @@ namespace ts { } function getNavigationBarItems(fileName: string): NavigationBarItem[] { - const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName); + return NavigationBar.getNavigationBarItems(syntaxTreeCache.getCurrentSourceFile(fileName)); + } - return NavigationBar.getNavigationBarItems(sourceFile); + function getNavigationTree(fileName: string): NavigationTree { + return NavigationBar.getNavigationTree(syntaxTreeCache.getCurrentSourceFile(fileName)); } function isTsOrTsxFile(fileName: string): boolean { @@ -1903,6 +1905,7 @@ namespace ts { getRenameInfo, findRenameLocations, getNavigationBarItems, + getNavigationTree, getOutliningSpans, getTodoComments, getBraceMatchingAtPosition, diff --git a/src/services/shims.ts b/src/services/shims.ts index 56ab852606c..7ed1786640d 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -224,6 +224,9 @@ namespace ts { */ getNavigationBarItems(fileName: string): string; + /** Returns a JSON-encoded value of the type ts.NavigationTree. */ + getNavigationTree(fileName: string): string; + /** * Returns a JSON-encoded value of the type: * { textSpan: { start: number, length: number }; hintSpan: { start: number, length: number }; bannerText: string; autoCollapse: boolean } [] = []; @@ -971,6 +974,13 @@ namespace ts { ); } + public getNavigationTree(fileName: string): string { + return this.forwardJSONCall( + `getNavigationTree('${fileName}')`, + () => this.languageService.getNavigationTree(fileName) + ); + } + public getOutliningSpans(fileName: string): string { return this.forwardJSONCall( `getOutliningSpans('${fileName}')`, diff --git a/src/services/types.ts b/src/services/types.ts index fafe274bce1..3d2bcf4c360 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -225,6 +225,7 @@ namespace ts { getNavigateToItems(searchValue: string, maxResultCount?: number, fileName?: string, excludeDtsFiles?: boolean): NavigateToItem[]; getNavigationBarItems(fileName: string): NavigationBarItem[]; + getNavigationTree(fileName: string): NavigationTree; getOutliningSpans(fileName: string): OutliningSpan[]; getTodoComments(fileName: string, descriptors: TodoCommentDescriptor[]): TodoComment[]; @@ -266,6 +267,12 @@ namespace ts { classificationType: string; // ClassificationTypeNames } + /** + * Navigation bar interface designed for visual studio's dual-column layout. + * This does not form a proper tree. + * The navbar is returned as a list of top-level items, each of which has a list of child items. + * Child items always have an empty array for their `childItems`. + */ export interface NavigationBarItem { text: string; kind: string; @@ -277,6 +284,26 @@ namespace ts { grayed: boolean; } + /** + * Node in a tree of nested declarations in a file. + * The top node is always a script or module node. + */ + export interface NavigationTree { + /** Name of the declaration, or a short description, e.g. "". */ + text: string; + /** A ScriptElementKind */ + kind: string; + /** ScriptElementKindModifier separated by commas, e.g. "public,abstract" */ + kindModifiers: string; + /** + * Spans of the nodes that generated this declaration. + * There will be more than one if this is the result of merging. + */ + spans: TextSpan[]; + /** Present if non-empty */ + childItems?: NavigationTree[]; + } + export interface TodoCommentDescriptor { text: string; priority: number; @@ -376,11 +403,11 @@ namespace ts { export interface EditorSettings { baseIndentSize?: number; - indentSize: number; - tabSize: number; - newLineCharacter: string; - convertTabsToSpaces: boolean; - indentStyle: IndentStyle; + indentSize?: number; + tabSize?: number; + newLineCharacter?: string; + convertTabsToSpaces?: boolean; + indentStyle?: IndentStyle; } /* @deprecated - consider using FormatCodeSettings instead */ @@ -401,19 +428,19 @@ namespace ts { } export interface FormatCodeSettings extends EditorSettings { - insertSpaceAfterCommaDelimiter: boolean; - insertSpaceAfterSemicolonInForStatements: boolean; - insertSpaceBeforeAndAfterBinaryOperators: boolean; - insertSpaceAfterKeywordsInControlFlowStatements: boolean; - insertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean; - insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean; - insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: boolean; + insertSpaceAfterCommaDelimiter?: boolean; + insertSpaceAfterSemicolonInForStatements?: boolean; + insertSpaceBeforeAndAfterBinaryOperators?: boolean; + insertSpaceAfterKeywordsInControlFlowStatements?: boolean; + insertSpaceAfterFunctionKeywordForAnonymousFunctions?: boolean; + insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis?: boolean; + insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets?: boolean; insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces?: boolean; - insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: boolean; - insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: boolean; + insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces?: boolean; + insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean; insertSpaceAfterTypeAssertion?: boolean; - placeOpenBraceOnNewLineForFunctions: boolean; - placeOpenBraceOnNewLineForControlBlocks: boolean; + placeOpenBraceOnNewLineForFunctions?: boolean; + placeOpenBraceOnNewLineForControlBlocks?: boolean; } export interface DefinitionInfo { diff --git a/tests/baselines/reference/declFileTypeAnnotationStringLiteral.types b/tests/baselines/reference/declFileTypeAnnotationStringLiteral.types index 6d9c17b4ab9..b1a85f3fc30 100644 --- a/tests/baselines/reference/declFileTypeAnnotationStringLiteral.types +++ b/tests/baselines/reference/declFileTypeAnnotationStringLiteral.types @@ -23,7 +23,7 @@ function foo(a: string): string | number { return a.length; >a.length : number ->a : string +>a : "hello" >length : number } diff --git a/tests/baselines/reference/literalTypes1.types b/tests/baselines/reference/literalTypes1.types index faff485d45a..1baaad3ff88 100644 --- a/tests/baselines/reference/literalTypes1.types +++ b/tests/baselines/reference/literalTypes1.types @@ -129,7 +129,7 @@ function f4(x: 0 | 1 | true | string) { >"def" : "def" x; ->x : string +>x : "abc" | "def" break; case null: @@ -163,7 +163,7 @@ function f5(x: string | number | boolean) { >"abc" : "abc" x; ->x : string +>x : "abc" break; case 0: @@ -173,7 +173,7 @@ function f5(x: string | number | boolean) { >1 : 1 x; ->x : number +>x : 0 | 1 break; case true: @@ -190,7 +190,7 @@ function f5(x: string | number | boolean) { >123 : 123 x; ->x : string | number +>x : "hello" | 123 break; default: diff --git a/tests/baselines/reference/literalTypes3.js b/tests/baselines/reference/literalTypes3.js new file mode 100644 index 00000000000..1989bb1d5a1 --- /dev/null +++ b/tests/baselines/reference/literalTypes3.js @@ -0,0 +1,125 @@ +//// [literalTypes3.ts] + +function f1(s: string) { + if (s === "foo") { + s; // "foo" + } + if (s === "foo" || s === "bar") { + s; // "foo" | "bar" + } +} + +function f2(s: string) { + switch (s) { + case "foo": + case "bar": + s; // "foo" | "bar" + case "baz": + s; // "foo" | "bar" | "baz" + break; + default: + s; // string + } +} + +function f3(s: string) { + return s === "foo" || s === "bar" ? s : undefined; // "foo" | "bar" | undefined +} + +function f4(x: number) { + if (x === 1 || x === 2) { + return x; // 1 | 2 + } + throw new Error(); +} + +function f5(x: number, y: 1 | 2) { + if (x === 0 || x === y) { + x; // 0 | 1 | 2 + } +} + +function f6(x: number, y: 1 | 2) { + if (y === x || 0 === x) { + x; // 0 | 1 | 2 + } +} + +function f7(x: number | "foo" | "bar", y: 1 | 2 | string) { + if (x === y) { + x; // "foo" | "bar" | 1 | 2 + } +} + +function f8(x: number | "foo" | "bar") { + switch (x) { + case 1: + case 2: + x; // 1 | 2 + break; + case "foo": + x; // "foo" + break; + default: + x; // number | "bar" + } +} + +//// [literalTypes3.js] +function f1(s) { + if (s === "foo") { + s; // "foo" + } + if (s === "foo" || s === "bar") { + s; // "foo" | "bar" + } +} +function f2(s) { + switch (s) { + case "foo": + case "bar": + s; // "foo" | "bar" + case "baz": + s; // "foo" | "bar" | "baz" + break; + default: + s; // string + } +} +function f3(s) { + return s === "foo" || s === "bar" ? s : undefined; // "foo" | "bar" | undefined +} +function f4(x) { + if (x === 1 || x === 2) { + return x; // 1 | 2 + } + throw new Error(); +} +function f5(x, y) { + if (x === 0 || x === y) { + x; // 0 | 1 | 2 + } +} +function f6(x, y) { + if (y === x || 0 === x) { + x; // 0 | 1 | 2 + } +} +function f7(x, y) { + if (x === y) { + x; // "foo" | "bar" | 1 | 2 + } +} +function f8(x) { + switch (x) { + case 1: + case 2: + x; // 1 | 2 + break; + case "foo": + x; // "foo" + break; + default: + x; // number | "bar" + } +} diff --git a/tests/baselines/reference/literalTypes3.symbols b/tests/baselines/reference/literalTypes3.symbols new file mode 100644 index 00000000000..6cc7ab007e6 --- /dev/null +++ b/tests/baselines/reference/literalTypes3.symbols @@ -0,0 +1,137 @@ +=== tests/cases/conformance/types/literal/literalTypes3.ts === + +function f1(s: string) { +>f1 : Symbol(f1, Decl(literalTypes3.ts, 0, 0)) +>s : Symbol(s, Decl(literalTypes3.ts, 1, 12)) + + if (s === "foo") { +>s : Symbol(s, Decl(literalTypes3.ts, 1, 12)) + + s; // "foo" +>s : Symbol(s, Decl(literalTypes3.ts, 1, 12)) + } + if (s === "foo" || s === "bar") { +>s : Symbol(s, Decl(literalTypes3.ts, 1, 12)) +>s : Symbol(s, Decl(literalTypes3.ts, 1, 12)) + + s; // "foo" | "bar" +>s : Symbol(s, Decl(literalTypes3.ts, 1, 12)) + } +} + +function f2(s: string) { +>f2 : Symbol(f2, Decl(literalTypes3.ts, 8, 1)) +>s : Symbol(s, Decl(literalTypes3.ts, 10, 12)) + + switch (s) { +>s : Symbol(s, Decl(literalTypes3.ts, 10, 12)) + + case "foo": + case "bar": + s; // "foo" | "bar" +>s : Symbol(s, Decl(literalTypes3.ts, 10, 12)) + + case "baz": + s; // "foo" | "bar" | "baz" +>s : Symbol(s, Decl(literalTypes3.ts, 10, 12)) + + break; + default: + s; // string +>s : Symbol(s, Decl(literalTypes3.ts, 10, 12)) + } +} + +function f3(s: string) { +>f3 : Symbol(f3, Decl(literalTypes3.ts, 21, 1)) +>s : Symbol(s, Decl(literalTypes3.ts, 23, 12)) + + return s === "foo" || s === "bar" ? s : undefined; // "foo" | "bar" | undefined +>s : Symbol(s, Decl(literalTypes3.ts, 23, 12)) +>s : Symbol(s, Decl(literalTypes3.ts, 23, 12)) +>s : Symbol(s, Decl(literalTypes3.ts, 23, 12)) +>undefined : Symbol(undefined) +} + +function f4(x: number) { +>f4 : Symbol(f4, Decl(literalTypes3.ts, 25, 1)) +>x : Symbol(x, Decl(literalTypes3.ts, 27, 12)) + + if (x === 1 || x === 2) { +>x : Symbol(x, Decl(literalTypes3.ts, 27, 12)) +>x : Symbol(x, Decl(literalTypes3.ts, 27, 12)) + + return x; // 1 | 2 +>x : Symbol(x, Decl(literalTypes3.ts, 27, 12)) + } + throw new Error(); +>Error : Symbol(Error, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +} + +function f5(x: number, y: 1 | 2) { +>f5 : Symbol(f5, Decl(literalTypes3.ts, 32, 1)) +>x : Symbol(x, Decl(literalTypes3.ts, 34, 12)) +>y : Symbol(y, Decl(literalTypes3.ts, 34, 22)) + + if (x === 0 || x === y) { +>x : Symbol(x, Decl(literalTypes3.ts, 34, 12)) +>x : Symbol(x, Decl(literalTypes3.ts, 34, 12)) +>y : Symbol(y, Decl(literalTypes3.ts, 34, 22)) + + x; // 0 | 1 | 2 +>x : Symbol(x, Decl(literalTypes3.ts, 34, 12)) + } +} + +function f6(x: number, y: 1 | 2) { +>f6 : Symbol(f6, Decl(literalTypes3.ts, 38, 1)) +>x : Symbol(x, Decl(literalTypes3.ts, 40, 12)) +>y : Symbol(y, Decl(literalTypes3.ts, 40, 22)) + + if (y === x || 0 === x) { +>y : Symbol(y, Decl(literalTypes3.ts, 40, 22)) +>x : Symbol(x, Decl(literalTypes3.ts, 40, 12)) +>x : Symbol(x, Decl(literalTypes3.ts, 40, 12)) + + x; // 0 | 1 | 2 +>x : Symbol(x, Decl(literalTypes3.ts, 40, 12)) + } +} + +function f7(x: number | "foo" | "bar", y: 1 | 2 | string) { +>f7 : Symbol(f7, Decl(literalTypes3.ts, 44, 1)) +>x : Symbol(x, Decl(literalTypes3.ts, 46, 12)) +>y : Symbol(y, Decl(literalTypes3.ts, 46, 38)) + + if (x === y) { +>x : Symbol(x, Decl(literalTypes3.ts, 46, 12)) +>y : Symbol(y, Decl(literalTypes3.ts, 46, 38)) + + x; // "foo" | "bar" | 1 | 2 +>x : Symbol(x, Decl(literalTypes3.ts, 46, 12)) + } +} + +function f8(x: number | "foo" | "bar") { +>f8 : Symbol(f8, Decl(literalTypes3.ts, 50, 1)) +>x : Symbol(x, Decl(literalTypes3.ts, 52, 12)) + + switch (x) { +>x : Symbol(x, Decl(literalTypes3.ts, 52, 12)) + + case 1: + case 2: + x; // 1 | 2 +>x : Symbol(x, Decl(literalTypes3.ts, 52, 12)) + + break; + case "foo": + x; // "foo" +>x : Symbol(x, Decl(literalTypes3.ts, 52, 12)) + + break; + default: + x; // number | "bar" +>x : Symbol(x, Decl(literalTypes3.ts, 52, 12)) + } +} diff --git a/tests/baselines/reference/literalTypes3.types b/tests/baselines/reference/literalTypes3.types new file mode 100644 index 00000000000..6161bc4b72a --- /dev/null +++ b/tests/baselines/reference/literalTypes3.types @@ -0,0 +1,177 @@ +=== tests/cases/conformance/types/literal/literalTypes3.ts === + +function f1(s: string) { +>f1 : (s: string) => void +>s : string + + if (s === "foo") { +>s === "foo" : boolean +>s : string +>"foo" : "foo" + + s; // "foo" +>s : "foo" + } + if (s === "foo" || s === "bar") { +>s === "foo" || s === "bar" : boolean +>s === "foo" : boolean +>s : string +>"foo" : "foo" +>s === "bar" : boolean +>s : string +>"bar" : "bar" + + s; // "foo" | "bar" +>s : "foo" | "bar" + } +} + +function f2(s: string) { +>f2 : (s: string) => void +>s : string + + switch (s) { +>s : string + + case "foo": +>"foo" : "foo" + + case "bar": +>"bar" : "bar" + + s; // "foo" | "bar" +>s : "foo" | "bar" + + case "baz": +>"baz" : "baz" + + s; // "foo" | "bar" | "baz" +>s : "foo" | "bar" | "baz" + + break; + default: + s; // string +>s : string + } +} + +function f3(s: string) { +>f3 : (s: string) => "foo" | "bar" | undefined +>s : string + + return s === "foo" || s === "bar" ? s : undefined; // "foo" | "bar" | undefined +>s === "foo" || s === "bar" ? s : undefined : "foo" | "bar" | undefined +>s === "foo" || s === "bar" : boolean +>s === "foo" : boolean +>s : string +>"foo" : "foo" +>s === "bar" : boolean +>s : string +>"bar" : "bar" +>s : "foo" | "bar" +>undefined : undefined +} + +function f4(x: number) { +>f4 : (x: number) => 1 | 2 +>x : number + + if (x === 1 || x === 2) { +>x === 1 || x === 2 : boolean +>x === 1 : boolean +>x : number +>1 : 1 +>x === 2 : boolean +>x : number +>2 : 2 + + return x; // 1 | 2 +>x : 1 | 2 + } + throw new Error(); +>new Error() : Error +>Error : ErrorConstructor +} + +function f5(x: number, y: 1 | 2) { +>f5 : (x: number, y: 1 | 2) => void +>x : number +>y : 1 | 2 + + if (x === 0 || x === y) { +>x === 0 || x === y : boolean +>x === 0 : boolean +>x : number +>0 : 0 +>x === y : boolean +>x : number +>y : 1 | 2 + + x; // 0 | 1 | 2 +>x : 1 | 2 | 0 + } +} + +function f6(x: number, y: 1 | 2) { +>f6 : (x: number, y: 1 | 2) => void +>x : number +>y : 1 | 2 + + if (y === x || 0 === x) { +>y === x || 0 === x : boolean +>y === x : boolean +>y : 1 | 2 +>x : number +>0 === x : boolean +>0 : 0 +>x : number + + x; // 0 | 1 | 2 +>x : 1 | 2 | 0 + } +} + +function f7(x: number | "foo" | "bar", y: 1 | 2 | string) { +>f7 : (x: number | "foo" | "bar", y: string | 1 | 2) => void +>x : number | "foo" | "bar" +>y : string | 1 | 2 + + if (x === y) { +>x === y : boolean +>x : number | "foo" | "bar" +>y : string | 1 | 2 + + x; // "foo" | "bar" | 1 | 2 +>x : "foo" | "bar" | 1 | 2 + } +} + +function f8(x: number | "foo" | "bar") { +>f8 : (x: number | "foo" | "bar") => void +>x : number | "foo" | "bar" + + switch (x) { +>x : number | "foo" | "bar" + + case 1: +>1 : 1 + + case 2: +>2 : 2 + + x; // 1 | 2 +>x : 1 | 2 + + break; + case "foo": +>"foo" : "foo" + + x; // "foo" +>x : "foo" + + break; + default: + x; // number | "bar" +>x : number | "bar" + } +} diff --git a/tests/baselines/reference/narrowedConstInMethod.js b/tests/baselines/reference/narrowedConstInMethod.js new file mode 100644 index 00000000000..f4cdc3def91 --- /dev/null +++ b/tests/baselines/reference/narrowedConstInMethod.js @@ -0,0 +1,40 @@ +//// [narrowedConstInMethod.ts] + +function f() { + const x: string | null = {}; + if (x !== null) { + return { + bar() { return x.length; } // Error: possibly null x + }; + } +} + +function f2() { + const x: string | null = {}; + if (x !== null) { + return class { + bar() { return x.length; } // Error: possibly null x + }; + } +} + +//// [narrowedConstInMethod.js] +function f() { + var x = {}; + if (x !== null) { + return { + bar: function () { return x.length; } // Error: possibly null x + }; + } +} +function f2() { + var x = {}; + if (x !== null) { + return (function () { + function class_1() { + } + class_1.prototype.bar = function () { return x.length; }; // Error: possibly null x + return class_1; + }()); + } +} diff --git a/tests/baselines/reference/narrowedConstInMethod.symbols b/tests/baselines/reference/narrowedConstInMethod.symbols new file mode 100644 index 00000000000..1fd05dcea5e --- /dev/null +++ b/tests/baselines/reference/narrowedConstInMethod.symbols @@ -0,0 +1,41 @@ +=== tests/cases/compiler/narrowedConstInMethod.ts === + +function f() { +>f : Symbol(f, Decl(narrowedConstInMethod.ts, 0, 0)) + + const x: string | null = {}; +>x : Symbol(x, Decl(narrowedConstInMethod.ts, 2, 9)) + + if (x !== null) { +>x : Symbol(x, Decl(narrowedConstInMethod.ts, 2, 9)) + + return { + bar() { return x.length; } // Error: possibly null x +>bar : Symbol(bar, Decl(narrowedConstInMethod.ts, 4, 16)) +>x.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(narrowedConstInMethod.ts, 2, 9)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + + }; + } +} + +function f2() { +>f2 : Symbol(f2, Decl(narrowedConstInMethod.ts, 8, 1)) + + const x: string | null = {}; +>x : Symbol(x, Decl(narrowedConstInMethod.ts, 11, 9)) + + if (x !== null) { +>x : Symbol(x, Decl(narrowedConstInMethod.ts, 11, 9)) + + return class { + bar() { return x.length; } // Error: possibly null x +>bar : Symbol((Anonymous class).bar, Decl(narrowedConstInMethod.ts, 13, 22)) +>x.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(narrowedConstInMethod.ts, 11, 9)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + + }; + } +} diff --git a/tests/baselines/reference/narrowedConstInMethod.types b/tests/baselines/reference/narrowedConstInMethod.types new file mode 100644 index 00000000000..a73f2edfccb --- /dev/null +++ b/tests/baselines/reference/narrowedConstInMethod.types @@ -0,0 +1,55 @@ +=== tests/cases/compiler/narrowedConstInMethod.ts === + +function f() { +>f : () => { bar(): number; } | undefined + + const x: string | null = {}; +>x : string | null +>null : null +>{} : any +>{} : {} + + if (x !== null) { +>x !== null : boolean +>x : string | null +>null : null + + return { +>{ bar() { return x.length; } // Error: possibly null x } : { bar(): number; } + + bar() { return x.length; } // Error: possibly null x +>bar : () => number +>x.length : number +>x : string +>length : number + + }; + } +} + +function f2() { +>f2 : () => typeof (Anonymous class) | undefined + + const x: string | null = {}; +>x : string | null +>null : null +>{} : any +>{} : {} + + if (x !== null) { +>x !== null : boolean +>x : string | null +>null : null + + return class { +>class { bar() { return x.length; } // Error: possibly null x } : typeof (Anonymous class) + + bar() { return x.length; } // Error: possibly null x +>bar : () => number +>x.length : number +>x : string +>length : number + + }; + } +} diff --git a/tests/baselines/reference/sourceMapValidationIfElse.types b/tests/baselines/reference/sourceMapValidationIfElse.types index b4a76d55647..87103b792e7 100644 --- a/tests/baselines/reference/sourceMapValidationIfElse.types +++ b/tests/baselines/reference/sourceMapValidationIfElse.types @@ -10,7 +10,7 @@ if (i == 10) { i++; >i++ : number ->i : number +>i : 10 } else { @@ -22,7 +22,7 @@ if (i == 10) { i++; >i++ : number ->i : number +>i : 10 } else if (i == 20) { >i == 20 : boolean @@ -31,7 +31,7 @@ else if (i == 20) { i--; >i-- : number ->i : number +>i : 20 } else if (i == 30) { >i == 30 : boolean diff --git a/tests/baselines/reference/sourceMapValidationSwitch.types b/tests/baselines/reference/sourceMapValidationSwitch.types index 9df86ee2132..359cabbfabe 100644 --- a/tests/baselines/reference/sourceMapValidationSwitch.types +++ b/tests/baselines/reference/sourceMapValidationSwitch.types @@ -11,7 +11,7 @@ switch (x) { x++; >x++ : number ->x : number +>x : 5 break; case 10: @@ -19,7 +19,7 @@ switch (x) { { x--; >x-- : number ->x : number +>x : 10 break; } @@ -39,7 +39,7 @@ switch (x) x++; >x++ : number ->x : number +>x : 5 break; case 10: @@ -47,7 +47,7 @@ switch (x) { x--; >x-- : number ->x : number +>x : 10 break; } diff --git a/tests/baselines/reference/sourceMapValidationWhile.types b/tests/baselines/reference/sourceMapValidationWhile.types index 71b50d86736..8769d98ef25 100644 --- a/tests/baselines/reference/sourceMapValidationWhile.types +++ b/tests/baselines/reference/sourceMapValidationWhile.types @@ -10,7 +10,7 @@ while (a == 10) { a++; >a++ : number ->a : number +>a : 10 } while (a == 10) >a == 10 : boolean @@ -19,5 +19,5 @@ while (a == 10) { a++; >a++ : number ->a : number +>a : 10 } diff --git a/tests/baselines/reference/stringLiteralTypesInUnionTypes02.types b/tests/baselines/reference/stringLiteralTypesInUnionTypes02.types index 0be891ade44..85378108298 100644 --- a/tests/baselines/reference/stringLiteralTypesInUnionTypes02.types +++ b/tests/baselines/reference/stringLiteralTypesInUnionTypes02.types @@ -19,7 +19,7 @@ if (x === "foo") { let a = x; >a : string ->x : string +>x : "foo" } else if (x !== "bar") { >x !== "bar" : boolean @@ -35,7 +35,7 @@ else if (x !== "bar") { else { let c = x; >c : string ->x : string +>x : "bar" let d = y; >d : string @@ -43,7 +43,7 @@ else { let e: (typeof x) | (typeof y) = c || d; >e : string ->x : string +>x : "bar" >y : string >c || d : string >c : string diff --git a/tests/baselines/reference/throwInEnclosingStatements.types b/tests/baselines/reference/throwInEnclosingStatements.types index 4955b9243ae..2d99ac435ae 100644 --- a/tests/baselines/reference/throwInEnclosingStatements.types +++ b/tests/baselines/reference/throwInEnclosingStatements.types @@ -25,7 +25,7 @@ switch (y) { >'a' : "a" throw y; ->y : string +>y : "a" default: throw y; diff --git a/tests/baselines/reference/umd5.errors.txt b/tests/baselines/reference/umd5.errors.txt index 9628ad738db..5595de8de29 100644 --- a/tests/baselines/reference/umd5.errors.txt +++ b/tests/baselines/reference/umd5.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/externalModules/a.ts(6,9): error TS2686: Identifier 'Foo' must be imported from a module +tests/cases/conformance/externalModules/a.ts(6,9): error TS2686: 'Foo' refers to a UMD global, but the current file is a module. Consider adding an import instead. ==== tests/cases/conformance/externalModules/a.ts (1 errors) ==== @@ -9,7 +9,7 @@ tests/cases/conformance/externalModules/a.ts(6,9): error TS2686: Identifier 'Foo // should error let z = Foo; ~~~ -!!! error TS2686: Identifier 'Foo' must be imported from a module +!!! error TS2686: 'Foo' refers to a UMD global, but the current file is a module. Consider adding an import instead. ==== tests/cases/conformance/externalModules/foo.d.ts (0 errors) ==== diff --git a/tests/baselines/reference/umd8.errors.txt b/tests/baselines/reference/umd8.errors.txt index 9396c8c5450..26c8adef561 100644 --- a/tests/baselines/reference/umd8.errors.txt +++ b/tests/baselines/reference/umd8.errors.txt @@ -1,4 +1,4 @@ -tests/cases/conformance/externalModules/a.ts(7,14): error TS2686: Identifier 'Foo' must be imported from a module +tests/cases/conformance/externalModules/a.ts(7,14): error TS2686: 'Foo' refers to a UMD global, but the current file is a module. Consider adding an import instead. ==== tests/cases/conformance/externalModules/a.ts (1 errors) ==== @@ -10,7 +10,7 @@ tests/cases/conformance/externalModules/a.ts(7,14): error TS2686: Identifier 'Fo let z: Foo.SubThing; // OK in ns position let x: any = Foo; // Not OK in value position ~~~ -!!! error TS2686: Identifier 'Foo' must be imported from a module +!!! error TS2686: 'Foo' refers to a UMD global, but the current file is a module. Consider adding an import instead. ==== tests/cases/conformance/externalModules/foo.d.ts (0 errors) ==== diff --git a/tests/cases/compiler/narrowedConstInMethod.ts b/tests/cases/compiler/narrowedConstInMethod.ts new file mode 100644 index 00000000000..3ddf97a8df3 --- /dev/null +++ b/tests/cases/compiler/narrowedConstInMethod.ts @@ -0,0 +1,19 @@ +// @strictNullChecks: true + +function f() { + const x: string | null = {}; + if (x !== null) { + return { + bar() { return x.length; } // Error: possibly null x + }; + } +} + +function f2() { + const x: string | null = {}; + if (x !== null) { + return class { + bar() { return x.length; } // Error: possibly null x + }; + } +} \ No newline at end of file diff --git a/tests/cases/conformance/types/literal/literalTypes3.ts b/tests/cases/conformance/types/literal/literalTypes3.ts new file mode 100644 index 00000000000..2aa3f1020e2 --- /dev/null +++ b/tests/cases/conformance/types/literal/literalTypes3.ts @@ -0,0 +1,66 @@ +// @strictNullChecks: true + +function f1(s: string) { + if (s === "foo") { + s; // "foo" + } + if (s === "foo" || s === "bar") { + s; // "foo" | "bar" + } +} + +function f2(s: string) { + switch (s) { + case "foo": + case "bar": + s; // "foo" | "bar" + case "baz": + s; // "foo" | "bar" | "baz" + break; + default: + s; // string + } +} + +function f3(s: string) { + return s === "foo" || s === "bar" ? s : undefined; // "foo" | "bar" | undefined +} + +function f4(x: number) { + if (x === 1 || x === 2) { + return x; // 1 | 2 + } + throw new Error(); +} + +function f5(x: number, y: 1 | 2) { + if (x === 0 || x === y) { + x; // 0 | 1 | 2 + } +} + +function f6(x: number, y: 1 | 2) { + if (y === x || 0 === x) { + x; // 0 | 1 | 2 + } +} + +function f7(x: number | "foo" | "bar", y: 1 | 2 | string) { + if (x === y) { + x; // "foo" | "bar" | 1 | 2 + } +} + +function f8(x: number | "foo" | "bar") { + switch (x) { + case 1: + case 2: + x; // 1 | 2 + break; + case "foo": + x; // "foo" + break; + default: + x; // number | "bar" + } +} \ No newline at end of file diff --git a/tests/cases/fourslash/completionListInImportClause04.ts b/tests/cases/fourslash/completionListInImportClause04.ts new file mode 100644 index 00000000000..672c754e807 --- /dev/null +++ b/tests/cases/fourslash/completionListInImportClause04.ts @@ -0,0 +1,20 @@ +/// + +// @Filename: foo.d.ts +//// declare class Foo { +//// static prop1(x: number): number; +//// static prop1(x: string): string; +//// static prop2(x: boolean): boolean; +//// } +//// export = Foo; /*2*/ + +// @Filename: app.ts +////import {/*1*/} from './foo'; + +goTo.marker('1'); +verify.completionListContains('prop1'); +verify.completionListContains('prop2'); +verify.not.completionListContains('Foo'); +verify.numberOfErrorsInCurrentFile(0); +goTo.marker('2'); +verify.numberOfErrorsInCurrentFile(0); diff --git a/tests/cases/fourslash/deleteClassWithEnumPresent.ts b/tests/cases/fourslash/deleteClassWithEnumPresent.ts index eb40a27bcd7..8914e0020a0 100644 --- a/tests/cases/fourslash/deleteClassWithEnumPresent.ts +++ b/tests/cases/fourslash/deleteClassWithEnumPresent.ts @@ -5,6 +5,32 @@ goTo.marker(); edit.deleteAtCaret('class Bar { }'.length); + +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "Foo", + "kind": "enum", + "childItems": [ + { + "text": "a", + "kind": "const" + }, + { + "text": "b", + "kind": "const" + }, + { + "text": "c", + "kind": "const" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 5e8666e8670..0a72d295295 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -212,6 +212,7 @@ declare namespace FourSlashInterface { codeFixAtPosition(expectedText: string, errorCode?: number): void; navigationBar(json: any): void; + navigationTree(json: any): void; navigationItemsListCount(count: number, searchValue: string, matchKind?: string, fileName?: string): void; navigationItemsListContains(name: string, kind: string, searchValue: string, matchKind: string, fileName?: string, parentName?: string): void; occurrencesAtPositionContains(range: Range, isWriteAccess?: boolean): void; diff --git a/tests/cases/fourslash/getNavigationBarItems.ts b/tests/cases/fourslash/getNavigationBarItems.ts index 8041ba3b464..4bcfc3e18aa 100644 --- a/tests/cases/fourslash/getNavigationBarItems.ts +++ b/tests/cases/fourslash/getNavigationBarItems.ts @@ -5,6 +5,27 @@ //// ["bar"]: string; ////} +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "C", + "kind": "class", + "childItems": [ + { + "text": "[\"bar\"]", + "kind": "property" + }, + { + "text": "foo", + "kind": "property" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", @@ -31,4 +52,4 @@ verify.navigationBar([ ], "indent": 1 } -]) +]); diff --git a/tests/cases/fourslash/navbar_const.ts b/tests/cases/fourslash/navbar_const.ts index faaedb54482..2d3e3b919d0 100644 --- a/tests/cases/fourslash/navbar_const.ts +++ b/tests/cases/fourslash/navbar_const.ts @@ -2,6 +2,17 @@ //// const c = 0; +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "c", + "kind": "const" + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navbar_contains-no-duplicates.ts b/tests/cases/fourslash/navbar_contains-no-duplicates.ts index ba48c4a93dd..f4b52bb09a1 100644 --- a/tests/cases/fourslash/navbar_contains-no-duplicates.ts +++ b/tests/cases/fourslash/navbar_contains-no-duplicates.ts @@ -27,6 +27,83 @@ //// export var x = 3; //// } +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "ABC", + "kind": "class", + "childItems": [ + { + "text": "foo", + "kind": "method", + "kindModifiers": "public" + } + ] + }, + { + "text": "ABC", + "kind": "module", + "childItems": [ + { + "text": "x", + "kind": "var", + "kindModifiers": "export" + } + ] + }, + { + "text": "Windows", + "kind": "module", + "kindModifiers": "declare", + "childItems": [ + { + "text": "Foundation", + "kind": "module", + "kindModifiers": "export,declare", + "childItems": [ + { + "text": "A", + "kind": "var", + "kindModifiers": "export,declare" + }, + { + "text": "B", + "kind": "var", + "kindModifiers": "export,declare" + }, + { + "text": "Test", + "kind": "class", + "kindModifiers": "export,declare", + "childItems": [ + { + "text": "wow", + "kind": "method", + "kindModifiers": "public,declare" + } + ] + }, + { + "text": "Test", + "kind": "module", + "kindModifiers": "export,declare", + "childItems": [ + { + "text": "Boom", + "kind": "function", + "kindModifiers": "export,declare" + } + ] + } + ] + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navbar_exportDefault.ts b/tests/cases/fourslash/navbar_exportDefault.ts index e547c9129a6..84f50610e6b 100644 --- a/tests/cases/fourslash/navbar_exportDefault.ts +++ b/tests/cases/fourslash/navbar_exportDefault.ts @@ -13,6 +13,17 @@ ////export default function Func { } goTo.file("a.ts"); +verify.navigationTree({ + "text": "\"a\"", + "kind": "module", + "childItems": [ + { + "text": "default", + "kind": "class", + "kindModifiers": "export" + } + ] +}); verify.navigationBar([ { "text": "\"a\"", @@ -34,6 +45,17 @@ verify.navigationBar([ ]); goTo.file("b.ts"); +verify.navigationTree({ + "text": "\"b\"", + "kind": "module", + "childItems": [ + { + "text": "C", + "kind": "class", + "kindModifiers": "export" + } + ] +}); verify.navigationBar([ { "text": "\"b\"", @@ -55,6 +77,17 @@ verify.navigationBar([ ]); goTo.file("c.ts"); +verify.navigationTree({ + "text": "\"c\"", + "kind": "module", + "childItems": [ + { + "text": "default", + "kind": "function", + "kindModifiers": "export" + } + ] +}); verify.navigationBar([ { "text": "\"c\"", @@ -76,6 +109,17 @@ verify.navigationBar([ ]); goTo.file("d.ts"); +verify.navigationTree({ + "text": "\"d\"", + "kind": "module", + "childItems": [ + { + "text": "Func", + "kind": "function", + "kindModifiers": "export" + } + ] +}); verify.navigationBar([ { "text": "\"d\"", diff --git a/tests/cases/fourslash/navbar_let.ts b/tests/cases/fourslash/navbar_let.ts index bd0e702bbf9..77e00ad7300 100644 --- a/tests/cases/fourslash/navbar_let.ts +++ b/tests/cases/fourslash/navbar_let.ts @@ -2,6 +2,17 @@ ////let c = 0; +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "c", + "kind": "let" + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions.ts b/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions.ts index 30e96739ab0..69fa697f7bc 100644 --- a/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions.ts +++ b/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions.ts @@ -26,6 +26,85 @@ //// (class { }); ////}) +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "", + "kind": "function", + "childItems": [ + { + "text": "nest", + "kind": "function", + "childItems": [ + { + "text": "moreNest", + "kind": "function" + } + ] + }, + { + "text": "x", + "kind": "function", + "childItems": [ + { + "text": "xx", + "kind": "function" + } + ] + }, + { + "text": "y", + "kind": "const", + "childItems": [ + { + "text": "foo", + "kind": "function" + } + ] + } + ] + }, + { + "text": "", + "kind": "function", + "childItems": [ + { + "text": "", + "kind": "function" + }, + { + "text": "z", + "kind": "function" + } + ] + }, + { + "text": "classes", + "kind": "function", + "childItems": [ + { + "text": "", + "kind": "class" + }, + { + "text": "cls2", + "kind": "class" + }, + { + "text": "cls3", + "kind": "class" + } + ] + }, + { + "text": "global.cls", + "kind": "class" + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions2.ts b/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions2.ts index 36b1e07cd8a..f6ce02e0dd0 100644 --- a/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions2.ts +++ b/tests/cases/fourslash/navigationBarAnonymousClassAndFunctionExpressions2.ts @@ -3,6 +3,39 @@ ////console.log(console.log(class Y {}, class X {}), console.log(class B {}, class A {})); ////console.log(class Cls { meth() {} }); +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "A", + "kind": "class" + }, + { + "text": "B", + "kind": "class" + }, + { + "text": "Cls", + "kind": "class", + "childItems": [ + { + "text": "meth", + "kind": "method" + } + ] + }, + { + "text": "X", + "kind": "class" + }, + { + "text": "Y", + "kind": "class" + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarFunctionIndirectlyInVariableDeclaration.ts b/tests/cases/fourslash/navigationBarFunctionIndirectlyInVariableDeclaration.ts index f14419a121a..a0ed5174f56 100644 --- a/tests/cases/fourslash/navigationBarFunctionIndirectlyInVariableDeclaration.ts +++ b/tests/cases/fourslash/navigationBarFunctionIndirectlyInVariableDeclaration.ts @@ -8,39 +8,64 @@ //// propB: function() {} ////}; -verify.navigationBar([ - { +verify.navigationTree({ "text": "", "kind": "script", "childItems": [ - { - "text": "a", - "kind": "var" - }, - { - "text": "b", - "kind": "var" - }, - { - "text": "propB", - "kind": "function" - } + { + "text": "a", + "kind": "var", + "childItems": [ + { + "text": "propA", + "kind": "function" + } + ] + }, + { + "text": "b", + "kind": "var" + }, + { + "text": "propB", + "kind": "function" + } ] - }, - { - "text": "a", - "kind": "var", - "childItems": [ - { - "text": "propA", - "kind": "function" - } - ], - "indent": 1 - }, - { - "text": "propB", - "kind": "function", - "indent": 1 - } +}); + +verify.navigationBar([ + { + "text": "", + "kind": "script", + "childItems": [ + { + "text": "a", + "kind": "var" + }, + { + "text": "b", + "kind": "var" + }, + { + "text": "propB", + "kind": "function" + } + ] + }, + { + "text": "a", + "kind": "var", + "childItems": [ + { + "text": "propA", + "kind": "function" + } + ], + "indent": 1 + }, + { + "text": "propB", + "kind": "function", + "indent": 1 + } ]); diff --git a/tests/cases/fourslash/navigationBarGetterAndSetter.ts b/tests/cases/fourslash/navigationBarGetterAndSetter.ts index 3ae2e0f60ac..ccf9e7c472e 100644 --- a/tests/cases/fourslash/navigationBarGetterAndSetter.ts +++ b/tests/cases/fourslash/navigationBarGetterAndSetter.ts @@ -8,6 +8,33 @@ //// } ////} +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "X", + "kind": "class", + "childItems": [ + { + "text": "x", + "kind": "getter" + }, + { + "text": "x", + "kind": "setter", + "childItems": [ + { + "text": "f", + "kind": "function" + } + ] + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarImports.ts b/tests/cases/fourslash/navigationBarImports.ts index 43cb99c556a..44f0d46b401 100644 --- a/tests/cases/fourslash/navigationBarImports.ts +++ b/tests/cases/fourslash/navigationBarImports.ts @@ -4,6 +4,29 @@ ////import c = require("m"); ////import * as d from "m"; +verify.navigationTree({ + "text": "\"navigationBarImports\"", + "kind": "module", + "childItems": [ + { + "text": "a", + "kind": "alias" + }, + { + "text": "b", + "kind": "alias" + }, + { + "text": "c", + "kind": "alias" + }, + { + "text": "d", + "kind": "alias" + } + ] +}); + verify.navigationBar([ { "text": "\"navigationBarImports\"", diff --git a/tests/cases/fourslash/navigationBarItemsBindingPatterns.ts b/tests/cases/fourslash/navigationBarItemsBindingPatterns.ts index ff1de04c07e..d2b8b24bcbf 100644 --- a/tests/cases/fourslash/navigationBarItemsBindingPatterns.ts +++ b/tests/cases/fourslash/navigationBarItemsBindingPatterns.ts @@ -6,6 +6,57 @@ ////const bar1, [c, d] ////var {e, x: [f, g]} = {a:1, x:[]}; +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "a", + "kind": "let" + }, + { + "text": "b", + "kind": "let" + }, + { + "text": "bar", + "kind": "var" + }, + { + "text": "bar1", + "kind": "const" + }, + { + "text": "c", + "kind": "const" + }, + { + "text": "d", + "kind": "const" + }, + { + "text": "e", + "kind": "var" + }, + { + "text": "f", + "kind": "var" + }, + { + "text": "foo", + "kind": "var" + }, + { + "text": "foo1", + "kind": "let" + }, + { + "text": "g", + "kind": "var" + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarItemsBindingPatternsInConstructor.ts b/tests/cases/fourslash/navigationBarItemsBindingPatternsInConstructor.ts index 61e34d0f30e..f1250d530d3 100644 --- a/tests/cases/fourslash/navigationBarItemsBindingPatternsInConstructor.ts +++ b/tests/cases/fourslash/navigationBarItemsBindingPatternsInConstructor.ts @@ -11,6 +11,41 @@ //// } ////} +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "A", + "kind": "class", + "childItems": [ + { + "text": "constructor", + "kind": "constructor" + }, + { + "text": "x", + "kind": "property" + } + ] + }, + { + "text": "B", + "kind": "class", + "childItems": [ + { + "text": "constructor", + "kind": "constructor" + }, + { + "text": "x", + "kind": "property" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarItemsEmptyConstructors.ts b/tests/cases/fourslash/navigationBarItemsEmptyConstructors.ts index 2e37f69b456..c300a1207d5 100644 --- a/tests/cases/fourslash/navigationBarItemsEmptyConstructors.ts +++ b/tests/cases/fourslash/navigationBarItemsEmptyConstructors.ts @@ -5,6 +5,23 @@ //// } ////} +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "Test", + "kind": "class", + "childItems": [ + { + "text": "constructor", + "kind": "constructor" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarItemsExports.ts b/tests/cases/fourslash/navigationBarItemsExports.ts index 3ec9b0a7138..1f29ae5af5b 100644 --- a/tests/cases/fourslash/navigationBarItemsExports.ts +++ b/tests/cases/fourslash/navigationBarItemsExports.ts @@ -9,6 +9,26 @@ //// ////export * from "a"; // no bindings here +verify.navigationTree({ + "text": "\"navigationBarItemsExports\"", + "kind": "module", + "childItems": [ + { + "text": "a", + "kind": "alias" + }, + { + "text": "B", + "kind": "alias" + }, + { + "text": "e", + "kind": "alias", + "kindModifiers": "export" + } + ] +}); + verify.navigationBar([ { "text": "\"navigationBarItemsExports\"", diff --git a/tests/cases/fourslash/navigationBarItemsFunctions.ts b/tests/cases/fourslash/navigationBarItemsFunctions.ts index b85e898065c..f43cd3effaf 100644 --- a/tests/cases/fourslash/navigationBarItemsFunctions.ts +++ b/tests/cases/fourslash/navigationBarItemsFunctions.ts @@ -14,6 +14,53 @@ //// var v = 10; ////} +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "baz", + "kind": "function", + "childItems": [ + { + "text": "v", + "kind": "var" + } + ] + }, + { + "text": "foo", + "kind": "function", + "childItems": [ + { + "text": "bar", + "kind": "function", + "childItems": [ + { + "text": "biz", + "kind": "function", + "childItems": [ + { + "text": "z", + "kind": "var" + } + ] + }, + { + "text": "y", + "kind": "var" + } + ] + }, + { + "text": "x", + "kind": "var" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarItemsFunctionsBroken.ts b/tests/cases/fourslash/navigationBarItemsFunctionsBroken.ts index b0238a1ef06..49ca40841d7 100644 --- a/tests/cases/fourslash/navigationBarItemsFunctionsBroken.ts +++ b/tests/cases/fourslash/navigationBarItemsFunctionsBroken.ts @@ -4,6 +4,23 @@ //// function; ////} +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "f", + "kind": "function", + "childItems": [ + { + "text": "", + "kind": "function" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarItemsFunctionsBroken2.ts b/tests/cases/fourslash/navigationBarItemsFunctionsBroken2.ts index 4f279446100..8ebfab8519b 100644 --- a/tests/cases/fourslash/navigationBarItemsFunctionsBroken2.ts +++ b/tests/cases/fourslash/navigationBarItemsFunctionsBroken2.ts @@ -5,6 +5,27 @@ //// function; ////} +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "", + "kind": "function" + }, + { + "text": "f", + "kind": "function", + "childItems": [ + { + "text": "", + "kind": "function" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarItemsImports.ts b/tests/cases/fourslash/navigationBarItemsImports.ts index ed398ec7f1d..b0ce515a56c 100644 --- a/tests/cases/fourslash/navigationBarItemsImports.ts +++ b/tests/cases/fourslash/navigationBarItemsImports.ts @@ -13,6 +13,44 @@ //// ////import * as ns from "a"; +verify.navigationTree({ + "text": "\"navigationBarItemsImports\"", + "kind": "module", + "childItems": [ + { + "text": "a", + "kind": "alias" + }, + { + "text": "B", + "kind": "alias" + }, + { + "text": "c", + "kind": "alias" + }, + { + "text": "D", + "kind": "alias" + }, + { + "text": "d1", + "kind": "alias" + }, + { + "text": "d2", + "kind": "alias" + }, + { + "text": "e", + "kind": "alias" + }, + { + "text": "ns", + "kind": "alias" + } + ] +}); verify.navigationBar([ { diff --git a/tests/cases/fourslash/navigationBarItemsInsideMethodsAndConstructors.ts b/tests/cases/fourslash/navigationBarItemsInsideMethodsAndConstructors.ts index a49f32d960e..35dff3af14c 100644 --- a/tests/cases/fourslash/navigationBarItemsInsideMethodsAndConstructors.ts +++ b/tests/cases/fourslash/navigationBarItemsInsideMethodsAndConstructors.ts @@ -18,6 +18,77 @@ //// emptyMethod() { } // Non child functions method should not be duplicated ////} +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "Class", + "kind": "class", + "childItems": [ + { + "text": "constructor", + "kind": "constructor", + "childItems": [ + { + "text": "LocalEnumInConstructor", + "kind": "enum", + "childItems": [ + { + "text": "LocalEnumMemberInConstructor", + "kind": "const" + } + ] + }, + { + "text": "LocalFunctionInConstructor", + "kind": "function" + }, + { + "text": "LocalInterfaceInConstrcutor", + "kind": "interface" + } + ] + }, + { + "text": "emptyMethod", + "kind": "method" + }, + { + "text": "method", + "kind": "method", + "childItems": [ + { + "text": "LocalEnumInMethod", + "kind": "enum", + "childItems": [ + { + "text": "LocalEnumMemberInMethod", + "kind": "const" + } + ] + }, + { + "text": "LocalFunctionInMethod", + "kind": "function", + "childItems": [ + { + "text": "LocalFunctionInLocalFunctionInMethod", + "kind": "function" + } + ] + }, + { + "text": "LocalInterfaceInMethod", + "kind": "interface" + } + ] + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarItemsItems.ts b/tests/cases/fourslash/navigationBarItemsItems.ts index e3d8f0e633c..69422dd0cc2 100644 --- a/tests/cases/fourslash/navigationBarItemsItems.ts +++ b/tests/cases/fourslash/navigationBarItemsItems.ts @@ -39,6 +39,114 @@ ////var p: IPoint = new Shapes.Point(3, 4); ////var dist = p.getDist(); +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "dist", + "kind": "var" + }, + { + "text": "IPoint", + "kind": "interface", + "childItems": [ + { + "text": "()", + "kind": "call" + }, + { + "text": "new()", + "kind": "construct" + }, + { + "text": "[]", + "kind": "index" + }, + { + "text": "getDist", + "kind": "method" + }, + { + "text": "prop", + "kind": "property" + } + ] + }, + { + "text": "p", + "kind": "var" + }, + { + "text": "Shapes", + "kind": "module", + "childItems": [ + { + "text": "Point", + "kind": "class", + "kindModifiers": "export", + "childItems": [ + { + "text": "constructor", + "kind": "constructor" + }, + { + "text": "getDist", + "kind": "method" + }, + { + "text": "getOrigin", + "kind": "method", + "kindModifiers": "private,static" + }, + { + "text": "origin", + "kind": "property", + "kindModifiers": "static" + }, + { + "text": "value", + "kind": "getter" + }, + { + "text": "value", + "kind": "setter" + }, + { + "text": "x", + "kind": "property", + "kindModifiers": "public" + }, + { + "text": "y", + "kind": "property", + "kindModifiers": "public" + } + ] + }, + { + "text": "Values", + "kind": "enum", + "childItems": [ + { + "text": "value1", + "kind": "const" + }, + { + "text": "value2", + "kind": "const" + }, + { + "text": "value3", + "kind": "const" + } + ] + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarItemsItems2.ts b/tests/cases/fourslash/navigationBarItemsItems2.ts index 6ab0827e8f9..fa5a5b09fac 100644 --- a/tests/cases/fourslash/navigationBarItemsItems2.ts +++ b/tests/cases/fourslash/navigationBarItemsItems2.ts @@ -6,6 +6,22 @@ goTo.marker(); edit.insertLine("module A"); edit.insert("export class "); +verify.navigationTree({ + "text": "\"navigationBarItemsItems2\"", + "kind": "module", + "childItems": [ + { + "text": "", + "kind": "class", + "kindModifiers": "export" + }, + { + "text": "A", + "kind": "module" + } + ] +}); + // should not crash verify.navigationBar([ { diff --git a/tests/cases/fourslash/navigationBarItemsItemsExternalModules.ts b/tests/cases/fourslash/navigationBarItemsItemsExternalModules.ts index 04091185dd0..705dc2227b3 100644 --- a/tests/cases/fourslash/navigationBarItemsItemsExternalModules.ts +++ b/tests/cases/fourslash/navigationBarItemsItemsExternalModules.ts @@ -4,6 +4,25 @@ //// public s: string; ////} +verify.navigationTree({ + "text": "\"navigationBarItemsItemsExternalModules\"", + "kind": "module", + "childItems": [ + { + "text": "Bar", + "kind": "class", + "kindModifiers": "export", + "childItems": [ + { + "text": "s", + "kind": "property", + "kindModifiers": "public" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "\"navigationBarItemsItemsExternalModules\"", diff --git a/tests/cases/fourslash/navigationBarItemsItemsExternalModules2.ts b/tests/cases/fourslash/navigationBarItemsItemsExternalModules2.ts index 4939091d944..c271050bc52 100644 --- a/tests/cases/fourslash/navigationBarItemsItemsExternalModules2.ts +++ b/tests/cases/fourslash/navigationBarItemsItemsExternalModules2.ts @@ -6,6 +6,30 @@ ////} ////export var x: number; +verify.navigationTree({ + "text": "\"file\"", + "kind": "module", + "childItems": [ + { + "text": "Bar", + "kind": "class", + "kindModifiers": "export", + "childItems": [ + { + "text": "s", + "kind": "property", + "kindModifiers": "public" + } + ] + }, + { + "text": "x", + "kind": "var", + "kindModifiers": "export" + } + ] +}); + verify.navigationBar([ { "text": "\"file\"", diff --git a/tests/cases/fourslash/navigationBarItemsItemsExternalModules3.ts b/tests/cases/fourslash/navigationBarItemsItemsExternalModules3.ts index 5ee760fabc6..91ac533d75c 100644 --- a/tests/cases/fourslash/navigationBarItemsItemsExternalModules3.ts +++ b/tests/cases/fourslash/navigationBarItemsItemsExternalModules3.ts @@ -6,6 +6,30 @@ ////} ////export var x: number; +verify.navigationTree({ + "text": "\"my fil\\\"e\"", + "kind": "module", + "childItems": [ + { + "text": "Bar", + "kind": "class", + "kindModifiers": "export", + "childItems": [ + { + "text": "s", + "kind": "property", + "kindModifiers": "public" + } + ] + }, + { + "text": "x", + "kind": "var", + "kindModifiers": "export" + } + ] +}); + verify.navigationBar([ { "text": "\"my fil\\\"e\"", diff --git a/tests/cases/fourslash/navigationBarItemsItemsModuleVariables.ts b/tests/cases/fourslash/navigationBarItemsItemsModuleVariables.ts index 9b8a65d0430..1beeffddb21 100644 --- a/tests/cases/fourslash/navigationBarItemsItemsModuleVariables.ts +++ b/tests/cases/fourslash/navigationBarItemsItemsModuleVariables.ts @@ -20,6 +20,23 @@ ////} goTo.marker("file1"); // nothing else should show up +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "Module1", + "kind": "module", + "childItems": [ + { + "text": "x", + "kind": "var", + "kindModifiers": "export" + } + ] + } + ] +}); verify.navigationBar([ { "text": "", @@ -46,6 +63,23 @@ verify.navigationBar([ ]); goTo.marker("file2"); +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "Module1.SubModule", + "kind": "module", + "childItems": [ + { + "text": "y", + "kind": "var", + "kindModifiers": "export" + } + ] + } + ] +}); verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarItemsMissingName1.ts b/tests/cases/fourslash/navigationBarItemsMissingName1.ts index 2a445a5e1ed..60123d92e71 100644 --- a/tests/cases/fourslash/navigationBarItemsMissingName1.ts +++ b/tests/cases/fourslash/navigationBarItemsMissingName1.ts @@ -3,6 +3,28 @@ //// foo() {} ////} +verify.navigationTree({ + "text": "\"navigationBarItemsMissingName1\"", + "kind": "module", + "childItems": [ + { + "text": "", + "kind": "function", + "kindModifiers": "export" + }, + { + "text": "C", + "kind": "class", + "childItems": [ + { + "text": "foo", + "kind": "method" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "\"navigationBarItemsMissingName1\"", diff --git a/tests/cases/fourslash/navigationBarItemsMissingName2.ts b/tests/cases/fourslash/navigationBarItemsMissingName2.ts index 9faeb6de902..ce92128c825 100644 --- a/tests/cases/fourslash/navigationBarItemsMissingName2.ts +++ b/tests/cases/fourslash/navigationBarItemsMissingName2.ts @@ -6,6 +6,23 @@ ////} // Anonymous classes are still included. +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "", + "kind": "class", + "childItems": [ + { + "text": "foo", + "kind": "method" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarItemsModules.ts b/tests/cases/fourslash/navigationBarItemsModules.ts index a41c75de550..fd5907e2bc7 100644 --- a/tests/cases/fourslash/navigationBarItemsModules.ts +++ b/tests/cases/fourslash/navigationBarItemsModules.ts @@ -27,6 +27,73 @@ //We have 8 module keywords, and 4 var keywords. //The declarations of A.B.C.x do not get merged, so the 4 vars are independent. //The two 'A' modules, however, do get merged, so in reality we have 7 modules. +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "'X2.Y2.Z2'", + "kind": "module", + "kindModifiers": "declare" + }, + { + "text": "\"X.Y.Z\"", + "kind": "module", + "kindModifiers": "declare" + }, + { + "text": "A", + "kind": "module", + "childItems": [ + { + "text": "B", + "kind": "module", + "childItems": [ + { + "text": "C", + "kind": "module", + "childItems": [ + { + "text": "x", + "kind": "var", + "kindModifiers": "declare" + } + ] + } + ] + }, + { + "text": "z", + "kind": "var", + "kindModifiers": "export" + } + ] + }, + { + "text": "A.B", + "kind": "module", + "childItems": [ + { + "text": "y", + "kind": "var", + "kindModifiers": "export" + } + ] + }, + { + "text": "A.B.C", + "kind": "module", + "childItems": [ + { + "text": "x", + "kind": "var", + "kindModifiers": "export" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarItemsMultilineStringIdentifiers.ts b/tests/cases/fourslash/navigationBarItemsMultilineStringIdentifiers.ts index dcf8894bb61..793844ac970 100644 --- a/tests/cases/fourslash/navigationBarItemsMultilineStringIdentifiers.ts +++ b/tests/cases/fourslash/navigationBarItemsMultilineStringIdentifiers.ts @@ -24,6 +24,56 @@ //// } ////} +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "\"Multiline\\\nMadness\"", + "kind": "module", + "kindModifiers": "declare" + }, + { + "text": "\"Multiline\\r\\nMadness\"", + "kind": "module", + "kindModifiers": "declare" + }, + { + "text": "\"MultilineMadness\"", + "kind": "module", + "kindModifiers": "declare" + }, + { + "text": "Bar", + "kind": "class", + "childItems": [ + { + "text": "'a1\\\\\\r\\nb'", + "kind": "property" + }, + { + "text": "'a2\\\n \\\n b'", + "kind": "method" + } + ] + }, + { + "text": "Foo", + "kind": "interface", + "childItems": [ + { + "text": "\"a1\\\\\\r\\nb\"", + "kind": "property" + }, + { + "text": "\"a2\\\n \\\n b\"", + "kind": "method" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarItemsPropertiesDefinedInConstructors.ts b/tests/cases/fourslash/navigationBarItemsPropertiesDefinedInConstructors.ts index b741084dab5..6e8e0ea350c 100644 --- a/tests/cases/fourslash/navigationBarItemsPropertiesDefinedInConstructors.ts +++ b/tests/cases/fourslash/navigationBarItemsPropertiesDefinedInConstructors.ts @@ -6,6 +6,43 @@ //// } ////} +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "List", + "kind": "class", + "childItems": [ + { + "text": "constructor", + "kind": "constructor", + "childItems": [ + { + "text": "local", + "kind": "var" + } + ] + }, + { + "text": "a", + "kind": "property", + "kindModifiers": "public" + }, + { + "text": "b", + "kind": "property", + "kindModifiers": "private" + }, + { + "text": "c", + "kind": "property" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarItemsSymbols1.ts b/tests/cases/fourslash/navigationBarItemsSymbols1.ts index ba57916028b..4326d7b4deb 100644 --- a/tests/cases/fourslash/navigationBarItemsSymbols1.ts +++ b/tests/cases/fourslash/navigationBarItemsSymbols1.ts @@ -6,6 +6,31 @@ //// get [Symbol.isConcatSpreadable]() { } ////} +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "C", + "kind": "class", + "childItems": [ + { + "text": "[Symbol.isConcatSpreadable]", + "kind": "getter" + }, + { + "text": "[Symbol.isRegExp]", + "kind": "property" + }, + { + "text": "[Symbol.iterator]", + "kind": "method" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarItemsSymbols2.ts b/tests/cases/fourslash/navigationBarItemsSymbols2.ts index 6812c88c150..64b076aaf0c 100644 --- a/tests/cases/fourslash/navigationBarItemsSymbols2.ts +++ b/tests/cases/fourslash/navigationBarItemsSymbols2.ts @@ -5,6 +5,27 @@ //// [Symbol.iterator](): string; ////} +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "I", + "kind": "interface", + "childItems": [ + { + "text": "[Symbol.isRegExp]", + "kind": "property" + }, + { + "text": "[Symbol.iterator]", + "kind": "method" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarItemsSymbols3.ts b/tests/cases/fourslash/navigationBarItemsSymbols3.ts index 661005b86d9..be001c75e0b 100644 --- a/tests/cases/fourslash/navigationBarItemsSymbols3.ts +++ b/tests/cases/fourslash/navigationBarItemsSymbols3.ts @@ -5,6 +5,17 @@ //// [Symbol.isRegExp] = 0 ////} +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "E", + "kind": "enum" + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarItemsTypeAlias.ts b/tests/cases/fourslash/navigationBarItemsTypeAlias.ts index cba3fb8789c..387a9925d82 100644 --- a/tests/cases/fourslash/navigationBarItemsTypeAlias.ts +++ b/tests/cases/fourslash/navigationBarItemsTypeAlias.ts @@ -2,6 +2,17 @@ ////type T = number | string; +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "T", + "kind": "type" + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarJsDoc.ts b/tests/cases/fourslash/navigationBarJsDoc.ts index 89049e6011a..8efce74d111 100644 --- a/tests/cases/fourslash/navigationBarJsDoc.ts +++ b/tests/cases/fourslash/navigationBarJsDoc.ts @@ -5,6 +5,25 @@ /////** @typedef {(string|number)} */ ////const x = 0; +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "NumberLike", + "kind": "type" + }, + { + "text": "x", + "kind": "const" + }, + { + "text": "x", + "kind": "type" + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarJsDocCommentWithNoTags.ts b/tests/cases/fourslash/navigationBarJsDocCommentWithNoTags.ts index 8746f135e4d..561bdf4a056 100644 --- a/tests/cases/fourslash/navigationBarJsDocCommentWithNoTags.ts +++ b/tests/cases/fourslash/navigationBarJsDocCommentWithNoTags.ts @@ -3,6 +3,18 @@ /////** Test */ ////export const Test = {} +verify.navigationTree({ + "text": "\"navigationBarJsDocCommentWithNoTags\"", + "kind": "module", + "childItems": [ + { + "text": "Test", + "kind": "const", + "kindModifiers": "export" + } + ] +}); + verify.navigationBar([ { "text": "\"navigationBarJsDocCommentWithNoTags\"", diff --git a/tests/cases/fourslash/navigationBarMerging.ts b/tests/cases/fourslash/navigationBarMerging.ts index 2798d186c96..ebf02c94466 100644 --- a/tests/cases/fourslash/navigationBarMerging.ts +++ b/tests/cases/fourslash/navigationBarMerging.ts @@ -11,6 +11,37 @@ //// function bar() {} ////} +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "a", + "kind": "module", + "childItems": [ + { + "text": "bar", + "kind": "function" + }, + { + "text": "foo", + "kind": "function" + } + ] + }, + { + "text": "b", + "kind": "module", + "childItems": [ + { + "text": "foo", + "kind": "function" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", @@ -60,6 +91,22 @@ verify.navigationBar([ ////function a() {} goTo.file("file2.ts"); + +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "a", + "kind": "function" + }, + { + "text": "a", + "kind": "module" + } + ] +}); + verify.navigationBar([ { "text": "", @@ -101,6 +148,34 @@ verify.navigationBar([ ////} goTo.file("file3.ts"); + +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "a", + "kind": "module", + "childItems": [ + { + "text": "A", + "kind": "interface", + "childItems": [ + { + "text": "bar", + "kind": "property" + }, + { + "text": "foo", + "kind": "property" + } + ] + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", @@ -147,6 +222,36 @@ verify.navigationBar([ ////module A.B { export var y; } goTo.file("file4.ts"); + +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "A", + "kind": "module", + "childItems": [ + { + "text": "x", + "kind": "var", + "kindModifiers": "export" + } + ] + }, + { + "text": "A.B", + "kind": "module", + "childItems": [ + { + "text": "y", + "kind": "var", + "kindModifiers": "export" + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/navigationBarNamespaceImportWithNoName.ts b/tests/cases/fourslash/navigationBarNamespaceImportWithNoName.ts index 732e2deb1dd..4c441728fdf 100644 --- a/tests/cases/fourslash/navigationBarNamespaceImportWithNoName.ts +++ b/tests/cases/fourslash/navigationBarNamespaceImportWithNoName.ts @@ -1,4 +1,16 @@ ////import *{} from 'foo'; + +verify.navigationTree({ + "text": "\"navigationBarNamespaceImportWithNoName\"", + "kind": "module", + "childItems": [ + { + "text": "", + "kind": "alias" + } + ] +}); + verify.navigationBar([ { "text": "\"navigationBarNamespaceImportWithNoName\"", diff --git a/tests/cases/fourslash/navigationBarVariables.ts b/tests/cases/fourslash/navigationBarVariables.ts index 93093df1306..98d5e816e8e 100644 --- a/tests/cases/fourslash/navigationBarVariables.ts +++ b/tests/cases/fourslash/navigationBarVariables.ts @@ -4,6 +4,25 @@ ////let y = 1; ////const z = 2; +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "x", + "kind": "var" + }, + { + "text": "y", + "kind": "let" + }, + { + "text": "z", + "kind": "const" + } + ] +}); + verify.navigationBar([ { "text": "", @@ -31,6 +50,26 @@ verify.navigationBar([ ////const [c] = 0; goTo.file("file2.ts"); + +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "a", + "kind": "var" + }, + { + "text": "b", + "kind": "let" + }, + { + "text": "c", + "kind": "const" + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts b/tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts index 978db18ab3b..212394159a8 100644 --- a/tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts +++ b/tests/cases/fourslash/server/jsdocTypedefTagNavigateTo.ts @@ -10,6 +10,29 @@ //// /** @type {/*1*/NumberLike} */ //// var numberLike; +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "numberLike", + "kind": "var" + }, + { + "text": "NumberLike", + "kind": "type" + }, + { + "text": "NumberLike2", + "kind": "var" + }, + { + "text": "NumberLike2", + "kind": "type" + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/server/navbar01.ts b/tests/cases/fourslash/server/navbar01.ts index a5b22ee1fa9..4a4f59bcf78 100644 --- a/tests/cases/fourslash/server/navbar01.ts +++ b/tests/cases/fourslash/server/navbar01.ts @@ -38,6 +38,114 @@ ////var p: IPoint = new Shapes.Point(3, 4); ////var dist = p.getDist(); +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "dist", + "kind": "var" + }, + { + "text": "IPoint", + "kind": "interface", + "childItems": [ + { + "text": "()", + "kind": "call" + }, + { + "text": "new()", + "kind": "construct" + }, + { + "text": "[]", + "kind": "index" + }, + { + "text": "getDist", + "kind": "method" + }, + { + "text": "prop", + "kind": "property" + } + ] + }, + { + "text": "p", + "kind": "var" + }, + { + "text": "Shapes", + "kind": "module", + "childItems": [ + { + "text": "Point", + "kind": "class", + "kindModifiers": "export", + "childItems": [ + { + "text": "constructor", + "kind": "constructor" + }, + { + "text": "getDist", + "kind": "method" + }, + { + "text": "getOrigin", + "kind": "method", + "kindModifiers": "private,static" + }, + { + "text": "origin", + "kind": "property", + "kindModifiers": "static" + }, + { + "text": "value", + "kind": "getter" + }, + { + "text": "value", + "kind": "setter" + }, + { + "text": "x", + "kind": "property", + "kindModifiers": "public" + }, + { + "text": "y", + "kind": "property", + "kindModifiers": "public" + } + ] + }, + { + "text": "Values", + "kind": "enum", + "childItems": [ + { + "text": "value1", + "kind": "const" + }, + { + "text": "value2", + "kind": "const" + }, + { + "text": "value3", + "kind": "const" + } + ] + } + ] + } + ] +}); + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/shims-pp/getNavigationBarItems.ts b/tests/cases/fourslash/shims-pp/getNavigationBarItems.ts index fba24bdcf77..627d4dac178 100644 --- a/tests/cases/fourslash/shims-pp/getNavigationBarItems.ts +++ b/tests/cases/fourslash/shims-pp/getNavigationBarItems.ts @@ -2,6 +2,17 @@ //// {| "itemName": "c", "kind": "const", "parentName": "" |}const c = 0; +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "c", + "kind": "const" + } + ] +}) + verify.navigationBar([ { "text": "", diff --git a/tests/cases/fourslash/shims/getNavigationBarItems.ts b/tests/cases/fourslash/shims/getNavigationBarItems.ts index fba24bdcf77..627d4dac178 100644 --- a/tests/cases/fourslash/shims/getNavigationBarItems.ts +++ b/tests/cases/fourslash/shims/getNavigationBarItems.ts @@ -2,6 +2,17 @@ //// {| "itemName": "c", "kind": "const", "parentName": "" |}const c = 0; +verify.navigationTree({ + "text": "", + "kind": "script", + "childItems": [ + { + "text": "c", + "kind": "const" + } + ] +}) + verify.navigationBar([ { "text": "",