diff --git a/Jakefile b/Jakefile index db8d670b0bf..4f2808dcbd1 100644 --- a/Jakefile +++ b/Jakefile @@ -57,7 +57,8 @@ var servicesSources = [ "services.ts", "shims.ts", "signatureHelp.ts", - "utilities.ts" + "utilities.ts", + "navigationBar.ts" ].map(function (f) { return path.join(servicesDirectory, f); })); diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index cc876f4e8cf..c9f9d6bf6e3 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -337,7 +337,7 @@ module ts { break; case SyntaxKind.SourceFile: if (isExternalModule(node)) { - bindAnonymousDeclaration(node, SymbolFlags.ValueModule, '"' + getModuleNameFromFilename((node).filename) + '"'); + bindAnonymousDeclaration(node, SymbolFlags.ValueModule, '"' + removeFileExtension((node).filename) + '"'); break; } default: diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index c2df5760e4e..c95ce3be317 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5658,6 +5658,10 @@ module ts { var isConstructor = (symbol.flags & SymbolFlags.Constructor) !== 0; function reportImplementationExpectedError(node: FunctionDeclaration): void { + if (node.name && node.name.kind === SyntaxKind.Missing) { + return; + } + var seen = false; var subsequentNode = forEachChild(node.parent, c => { if (seen) { diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 123bde2e719..4e74ec1b967 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -533,6 +533,43 @@ module ts { return pathLen > extLen && path.substr(pathLen - extLen, extLen) === extension; } + var supportedExtensions = [".d.ts", ".ts", ".js"]; + + export function removeFileExtension(path: string): string { + for (var i = 0; i < supportedExtensions.length; i++) { + var ext = supportedExtensions[i]; + + if (fileExtensionIs(path, ext)) { + return path.substr(0, path.length - ext.length); + } + } + + return path; + } + + var escapedCharsRegExp = /[\t\v\f\b\0\r\n\"\\\u2028\u2029\u0085]/g; + var escapedCharsMap: Map = { + "\t": "\\t", + "\v": "\\v", + "\f": "\\f", + "\b": "\\b", + "\0": "\\0", + "\r": "\\r", + "\n": "\\n", + "\"": "\\\"", + "\u2028": "\\u2028", // lineSeparator + "\u2029": "\\u2029", // paragraphSeparator + "\u0085": "\\u0085" // nextLine + }; + + /** NOTE: This *does not* support the full escape characters, it only supports the subset that can be used in file names + * or string literals. If the information encoded in the map changes, this needs to be revisited. */ + export function escapeString(s: string): string { + return escapedCharsRegExp.test(s) ? s.replace(escapedCharsRegExp, c => { + return escapedCharsMap[c] || c; + }) : s; + } + export interface ObjectAllocator { getNodeConstructor(kind: SyntaxKind): new () => Node; getSymbolConstructor(): new (flags: SymbolFlags, name: string) => Symbol; diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index a91637f2332..fb40117fb9b 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -56,10 +56,10 @@ module ts { function getOwnEmitOutputFilePath(sourceFile: SourceFile, extension: string) { if (compilerOptions.outDir) { - var emitOutputFilePathWithoutExtension = getModuleNameFromFilename(getSourceFilePathInNewDir(compilerOptions.outDir, sourceFile)); + var emitOutputFilePathWithoutExtension = removeFileExtension(getSourceFilePathInNewDir(compilerOptions.outDir, sourceFile)); } else { - var emitOutputFilePathWithoutExtension = getModuleNameFromFilename(sourceFile.filename); + var emitOutputFilePathWithoutExtension = removeFileExtension(sourceFile.filename); } return emitOutputFilePathWithoutExtension + extension; @@ -591,21 +591,6 @@ module ts { recordSourceMapSpan(comment.end); } - var escapedCharsRegExp = /[\t\v\f\b\0\r\n\"\u2028\u2029\u0085]/g; - var escapedCharsMap: Map = { - "\t": "\\t", - "\v": "\\v", - "\f": "\\f", - "\b": "\\b", - "\0": "\\0", - "\r": "\\r", - "\n": "\\n", - "\"": "\\\"", - "\u2028": "\\u2028", // lineSeparator - "\u2029": "\\u2029", // paragraphSeparator - "\u0085": "\\u0085" // nextLine - }; - function serializeSourceMapContents(version: number, file: string, sourceRoot: string, sources: string[], names: string[], mappings: string) { if (typeof JSON !== "undefined") { return JSON.stringify({ @@ -620,14 +605,6 @@ module ts { return "{\"version\":" + version + ",\"file\":\"" + escapeString(file) + "\",\"sourceRoot\":\"" + escapeString(sourceRoot) + "\",\"sources\":[" + serializeStringArray(sources) + "],\"names\":[" + serializeStringArray(names) + "],\"mappings\":\"" + escapeString(mappings) + "\"}"; - /** This does not support the full escape characters, it only supports the subset that can be used in file names - * or string literals. If the information encoded in the map changes, this needs to be revisited. */ - function escapeString(s: string): string { - return escapedCharsRegExp.test(s) ? s.replace(escapedCharsRegExp, c => { - return escapedCharsMap[c] || c; - }) : s; - } - function serializeStringArray(list: string[]): string { var output = ""; for (var i = 0, n = list.length; i < n; i++) { @@ -3164,7 +3141,7 @@ module ts { ? referencedFile.filename // Declaration file, use declaration file name : shouldEmitToOwnFile(referencedFile, compilerOptions) ? getOwnEmitOutputFilePath(referencedFile, ".d.ts") // Own output file so get the .d.ts file - : getModuleNameFromFilename(compilerOptions.out) + ".d.ts";// Global out file + : removeFileExtension(compilerOptions.out) + ".d.ts";// Global out file declFileName = getRelativePathToDirectoryOrUrl( getDirectoryPath(normalizeSlashes(jsFilePath)), @@ -3237,7 +3214,7 @@ module ts { } }); declarationOutput += synchronousDeclarationOutput.substring(appliedSyncOutputPos); - writeFile(getModuleNameFromFilename(jsFilePath) + ".d.ts", declarationOutput, compilerOptions.emitBOM); + writeFile(removeFileExtension(jsFilePath) + ".d.ts", declarationOutput, compilerOptions.emitBOM); } } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 13fe69cf1ba..422d133d5d0 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -17,22 +17,11 @@ module ts { return node; } - var moduleExtensions = [".d.ts", ".ts", ".js"]; - interface ReferenceComments { referencedFiles: FileReference[]; amdDependencies: string[]; } - export function getModuleNameFromFilename(filename: string) { - for (var i = 0; i < moduleExtensions.length; i++) { - var ext = moduleExtensions[i]; - var len = filename.length - ext.length; - if (len > 0 && filename.substr(len) === ext) return filename.substr(0, len); - } - return filename; - } - export function getSourceFileOfNode(node: Node): SourceFile { while (node && node.kind !== SyntaxKind.SourceFile) node = node.parent; return node; @@ -1107,7 +1096,10 @@ module ts { return finishNode(node); } error(Diagnostics.Identifier_expected); - return createMissingNode(); + + var node = createMissingNode(); + node.text = ""; + return node; } function parseIdentifier(): Identifier { diff --git a/src/services/getScriptLexicalStructureWalker.ts b/src/services/getScriptLexicalStructureWalker.ts deleted file mode 100644 index 94ed8a6de87..00000000000 --- a/src/services/getScriptLexicalStructureWalker.ts +++ /dev/null @@ -1,363 +0,0 @@ - -module TypeScript.Services { - export class NavigationBarItemGetter { - private hasGlobalNode = false; - - private getIndent(node: ISyntaxNode): number { - var indent = this.hasGlobalNode ? 1 : 0; - - var current = node.parent; - while (current != null) { - if (current.kind() == SyntaxKind.ModuleDeclaration || current.kind() === SyntaxKind.FunctionDeclaration) { - indent++; - } - - current = current.parent; - } - - return indent; - } - - private getKindModifiers(modifiers: TypeScript.ISyntaxToken[]): string { - var result: string[] = []; - - for (var i = 0, n = modifiers.length; i < n; i++) { - result.push(modifiers[i].text()); - } - - return result.length > 0 ? result.join(',') : ts.ScriptElementKindModifier.none; - } - - public getItems(node: TypeScript.SourceUnitSyntax): ts.NavigationBarItem[] { - return this.getItemsWorker(() => this.getTopLevelNodes(node), n => this.createTopLevelItem(n)); - } - - private getChildNodes(nodes: IModuleElementSyntax[]): ISyntaxNode[] { - var childNodes: ISyntaxNode[] = []; - - for (var i = 0, n = nodes.length; i < n; i++) { - var node = nodes[i]; - - if (node.kind() === SyntaxKind.FunctionDeclaration) { - childNodes.push(node); - } - else if (node.kind() === SyntaxKind.VariableStatement) { - var variableDeclaration = (node).variableDeclaration; - childNodes.push.apply(childNodes, variableDeclaration.variableDeclarators); - } - } - - return childNodes; - } - - private getTopLevelNodes(node: SourceUnitSyntax): ISyntaxNode[] { - var topLevelNodes: ISyntaxNode[] = []; - topLevelNodes.push(node); - - this.addTopLevelNodes(node.moduleElements, topLevelNodes); - - return topLevelNodes; - } - - private addTopLevelNodes(nodes: IModuleElementSyntax[], topLevelNodes: ISyntaxNode[]): void { - for (var i = 0, n = nodes.length; i < n; i++) { - var node = nodes[i]; - switch (node.kind()) { - case SyntaxKind.ClassDeclaration: - case SyntaxKind.EnumDeclaration: - case SyntaxKind.InterfaceDeclaration: - topLevelNodes.push(node); - break; - - case SyntaxKind.ModuleDeclaration: - var moduleDeclaration = node; - topLevelNodes.push(node); - this.addTopLevelNodes(moduleDeclaration.moduleElements, topLevelNodes); - break; - - case SyntaxKind.FunctionDeclaration: - var functionDeclaration = node; - if (this.isTopLevelFunctionDeclaration(functionDeclaration)) { - topLevelNodes.push(node); - this.addTopLevelNodes(functionDeclaration.block.statements, topLevelNodes); - } - break; - } - } - } - - public isTopLevelFunctionDeclaration(functionDeclaration: FunctionDeclarationSyntax) { - // A function declaration is 'top level' if it contains any function declarations - // within it. - return functionDeclaration.block && ArrayUtilities.any(functionDeclaration.block.statements, s => s.kind() === SyntaxKind.FunctionDeclaration); - } - - private getItemsWorker(getNodes: () => ISyntaxNode[], createItem: (n: ISyntaxNode) => ts.NavigationBarItem): ts.NavigationBarItem[] { - var items: ts.NavigationBarItem[] = []; - - var keyToItem = createIntrinsicsObject(); - - var nodes = getNodes(); - for (var i = 0, n = nodes.length; i < n; i++) { - var child = nodes[i]; - var item = createItem(child); - if (item != null) { - if (item.text.length > 0) { - var key = item.text + "-" + item.kind; - - var itemWithSameName = keyToItem[key]; - if (itemWithSameName) { - // We had an item with the same name. Merge these items together. - this.merge(itemWithSameName, item); - } - else { - keyToItem[key] = item; - items.push(item); - } - } - } - } - - return items; - } - - private merge(target: ts.NavigationBarItem, source: ts.NavigationBarItem) { - // First, add any spans in the source to the target. - target.spans.push.apply(target.spans, source.spans); - - if (source.childItems) { - if (!target.childItems) { - target.childItems = []; - } - - // Next, recursively merge or add any children in the source as appropriate. - outer: - for (var i = 0, n = source.childItems.length; i < n; i++) { - var sourceChild = source.childItems[i]; - - for (var j = 0, m = target.childItems.length; j < m; j++) { - var targetChild = target.childItems[j]; - - if (targetChild.text === sourceChild.text && targetChild.kind === sourceChild.kind) { - // Found a match. merge them. - this.merge(targetChild, sourceChild); - continue outer; - } - } - - // Didn't find a match, just add this child to the list. - target.childItems.push(sourceChild); - } - } - } - - private getNavigationBarItem(text: string, kind: string, kindModifiers: string, spans: TypeScript.TextSpan[], childItems: ts.NavigationBarItem[]= [], indent: number = 0): ts.NavigationBarItem { - return { - text: text, - kind: kind, - kindModifiers: kindModifiers, - spans: spans, - childItems: childItems, - indent: indent, - bolded: false, - grayed: false - }; - } - - private createChildItem(node: ISyntaxNode): ts.NavigationBarItem { - switch (node.kind()) { - case SyntaxKind.Parameter: - var parameter = node; - if (parameter.modifiers.length === 0) { - return null; - } - return this.getNavigationBarItem(parameter.identifier.text(), ts.ScriptElementKind.memberVariableElement, this.getKindModifiers(parameter.modifiers), [TextSpan.fromBounds(start(node), end(node))]); - - case SyntaxKind.MemberFunctionDeclaration: - var memberFunction = node; - return this.getNavigationBarItem(memberFunction.propertyName.text(), ts.ScriptElementKind.memberFunctionElement, this.getKindModifiers(memberFunction.modifiers), [TextSpan.fromBounds(start(node), end(node))]); - - case SyntaxKind.GetAccessor: - var getAccessor = node; - return this.getNavigationBarItem(getAccessor.propertyName.text(), ts.ScriptElementKind.memberGetAccessorElement, this.getKindModifiers(getAccessor.modifiers), [TextSpan.fromBounds(start(node), end(node))]); - - case SyntaxKind.SetAccessor: - var setAccessor = node; - return this.getNavigationBarItem(setAccessor.propertyName.text(), ts.ScriptElementKind.memberSetAccessorElement, this.getKindModifiers(setAccessor.modifiers), [TextSpan.fromBounds(start(node), end(node))]); - - case SyntaxKind.IndexSignature: - var indexSignature = node; - return this.getNavigationBarItem("[]", ts.ScriptElementKind.indexSignatureElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]); - - case SyntaxKind.EnumElement: - var enumElement = node; - return this.getNavigationBarItem(enumElement.propertyName.text(), ts.ScriptElementKind.memberVariableElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]); - - case SyntaxKind.CallSignature: - var callSignature = node; - return this.getNavigationBarItem("()", ts.ScriptElementKind.callSignatureElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]); - - case SyntaxKind.ConstructSignature: - var constructSignature = node; - return this.getNavigationBarItem("new()", ts.ScriptElementKind.constructSignatureElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]); - - case SyntaxKind.MethodSignature: - var methodSignature = node; - return this.getNavigationBarItem(methodSignature.propertyName.text(), ts.ScriptElementKind.memberFunctionElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]); - - case SyntaxKind.PropertySignature: - var propertySignature = node; - return this.getNavigationBarItem(propertySignature.propertyName.text(), ts.ScriptElementKind.memberVariableElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]); - - case SyntaxKind.FunctionDeclaration: - var functionDeclaration = node; - if (!this.isTopLevelFunctionDeclaration(functionDeclaration)) { - return this.getNavigationBarItem(functionDeclaration.identifier.text(), ts.ScriptElementKind.functionElement, this.getKindModifiers(functionDeclaration.modifiers), [TextSpan.fromBounds(start(node), end(node))]); - } - break; - - case SyntaxKind.MemberVariableDeclaration: - var memberVariableDeclaration = node; - return this.getNavigationBarItem(memberVariableDeclaration.variableDeclarator.propertyName.text(), ts.ScriptElementKind.memberVariableElement, this.getKindModifiers(memberVariableDeclaration.modifiers), [TextSpan.fromBounds(start(memberVariableDeclaration.variableDeclarator), end(memberVariableDeclaration.variableDeclarator))]); - - case SyntaxKind.VariableDeclarator: - var variableDeclarator = node; - return this.getNavigationBarItem(variableDeclarator.propertyName.text(), ts.ScriptElementKind.variableElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(variableDeclarator), end(variableDeclarator))]); - - case SyntaxKind.ConstructorDeclaration: - var constructorDeclaration = node; - return this.getNavigationBarItem("constructor", ts.ScriptElementKind.constructorImplementationElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]); - } - - return null; - } - - private createTopLevelItem(node: ISyntaxNode): ts.NavigationBarItem { - switch (node.kind()) { - case SyntaxKind.SourceUnit: - return this.createSourceUnitItem(node); - - case SyntaxKind.ClassDeclaration: - return this.createClassItem(node); - - case SyntaxKind.EnumDeclaration: - return this.createEnumItem(node); - - case SyntaxKind.InterfaceDeclaration: - return this.createIterfaceItem(node); - - case SyntaxKind.ModuleDeclaration: - return this.createModuleItem(node); - - case SyntaxKind.FunctionDeclaration: - return this.createFunctionItem(node); - } - - return null; - } - - private getModuleNames(node: TypeScript.ModuleDeclarationSyntax): string[] { - var result: string[] = []; - - if (node.stringLiteral) { - result.push(node.stringLiteral.text()); - } - else { - this.getModuleNamesHelper(node.name, result); - } - - return result; - } - - private getModuleNamesHelper(name: TypeScript.INameSyntax, result: string[]): void { - if (name.kind() === TypeScript.SyntaxKind.QualifiedName) { - var qualifiedName = name; - this.getModuleNamesHelper(qualifiedName.left, result); - result.push(qualifiedName.right.text()); - } - else { - result.push((name).text()); - } - } - - private createModuleItem(node: ModuleDeclarationSyntax): ts.NavigationBarItem { - var moduleNames = this.getModuleNames(node); - - var childItems = this.getItemsWorker(() => this.getChildNodes(node.moduleElements), n => this.createChildItem(n)); - - return this.getNavigationBarItem(moduleNames.join("."), - ts.ScriptElementKind.moduleElement, - this.getKindModifiers(node.modifiers), - [TextSpan.fromBounds(start(node), end(node))], - childItems, - this.getIndent(node)); - } - - private createFunctionItem(node: FunctionDeclarationSyntax) { - var childItems = this.getItemsWorker(() => node.block.statements, n => this.createChildItem(n)); - - return this.getNavigationBarItem(node.identifier.text(), - ts.ScriptElementKind.functionElement, - this.getKindModifiers(node.modifiers), - [TextSpan.fromBounds(start(node), end(node))], - childItems, - this.getIndent(node)); - } - - private createSourceUnitItem(node: SourceUnitSyntax): ts.NavigationBarItem { - var childItems = this.getItemsWorker(() => this.getChildNodes(node.moduleElements), n => this.createChildItem(n)); - - if (childItems === null || childItems.length === 0) { - return null; - } - - this.hasGlobalNode = true; - return this.getNavigationBarItem("", - ts.ScriptElementKind.moduleElement, - ts.ScriptElementKindModifier.none, - [TextSpan.fromBounds(start(node), end(node))], - childItems); - } - - private createClassItem(node: ClassDeclarationSyntax): ts.NavigationBarItem { - var constructor = ArrayUtilities.firstOrDefault( - node.classElements, n => n.kind() === SyntaxKind.ConstructorDeclaration); - - // Add the constructor parameters in as children of hte class (for property parameters). - var nodes: ISyntaxNode[] = constructor - ? (constructor.callSignature.parameterList.parameters).concat(node.classElements) - : node.classElements; - - var childItems = this.getItemsWorker(() => nodes, n => this.createChildItem(n)); - return this.getNavigationBarItem( - node.identifier.text(), - ts.ScriptElementKind.classElement, - this.getKindModifiers(node.modifiers), - [TextSpan.fromBounds(start(node), end(node))], - childItems, - this.getIndent(node)); - } - - private createEnumItem(node: TypeScript.EnumDeclarationSyntax): ts.NavigationBarItem { - var childItems = this.getItemsWorker(() => node.enumElements, n => this.createChildItem(n)); - return this.getNavigationBarItem( - node.identifier.text(), - ts.ScriptElementKind.enumElement, - this.getKindModifiers(node.modifiers), - [TextSpan.fromBounds(start(node), end(node))], - childItems, - this.getIndent(node)); - } - - private createIterfaceItem(node: TypeScript.InterfaceDeclarationSyntax): ts.NavigationBarItem { - var childItems = this.getItemsWorker(() => node.body.typeMembers, n => this.createChildItem(n)); - return this.getNavigationBarItem( - node.identifier.text(), - ts.ScriptElementKind.interfaceElement, - this.getKindModifiers(node.modifiers), - [TextSpan.fromBounds(start(node), end(node))], - childItems, - this.getIndent(node)); - } - } -} \ No newline at end of file diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts new file mode 100644 index 00000000000..5cf2dd90eea --- /dev/null +++ b/src/services/navigationBar.ts @@ -0,0 +1,389 @@ +/// +/// + +module ts.NavigationBar { + export function getNavigationBarItems(sourceFile: SourceFile): ts.NavigationBarItem[] { + // If the source file has any child items, then it included in the tree + // and takes lexical ownership of all other top-level items. + var hasGlobalNode = false; + + return getItemsWorker(getTopLevelNodes(sourceFile), createTopLevelItem); + + function getIndent(node: Node): number { + // If we have a global node in the tree, + // then it adds an extra layer of depth to all subnodes. + var indent = hasGlobalNode ? 1 : 0; + + var current = node.parent; + while (current) { + switch (current.kind) { + case SyntaxKind.ModuleDeclaration: + // If we have a module declared as A.B.C, it is more "intuitive" + // to say it only has a single layer of depth + do { + current = current.parent; + } while (current.kind === SyntaxKind.ModuleDeclaration); + + // fall through + case SyntaxKind.ClassDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.InterfaceDeclaration: + case SyntaxKind.FunctionDeclaration: + indent++; + } + + current = current.parent; + } + + return indent; + } + + function getChildNodes(nodes: Node[]): Node[] { + var childNodes: Node[] = []; + + for (var i = 0, n = nodes.length; i < n; i++) { + var node = nodes[i]; + + if (node.kind === SyntaxKind.FunctionDeclaration) { + childNodes.push(node); + } + else if (node.kind === SyntaxKind.VariableStatement) { + childNodes.push.apply(childNodes, (node).declarations); + } + } + + return childNodes; + } + + function getTopLevelNodes(node: SourceFile): Node[] { + var topLevelNodes: Node[] = []; + topLevelNodes.push(node); + + addTopLevelNodes(node.statements, topLevelNodes); + + return topLevelNodes; + } + + function addTopLevelNodes(nodes: Node[], topLevelNodes: Node[]): void { + for (var i = 0, n = nodes.length; i < n; i++) { + var node = nodes[i]; + switch (node.kind) { + case SyntaxKind.ClassDeclaration: + case SyntaxKind.EnumDeclaration: + case SyntaxKind.InterfaceDeclaration: + topLevelNodes.push(node); + break; + + case SyntaxKind.ModuleDeclaration: + var moduleDeclaration = node; + topLevelNodes.push(node); + addTopLevelNodes((getInnermostModule(moduleDeclaration).body).statements, topLevelNodes); + break; + + case SyntaxKind.FunctionDeclaration: + var functionDeclaration = node; + if (isTopLevelFunctionDeclaration(functionDeclaration)) { + topLevelNodes.push(node); + addTopLevelNodes((functionDeclaration.body).statements, topLevelNodes); + } + break; + } + } + } + + function isTopLevelFunctionDeclaration(functionDeclaration: FunctionDeclaration) { + // A function declaration is 'top level' if it contains any function declarations + // within it. + return functionDeclaration.kind === SyntaxKind.FunctionDeclaration && + functionDeclaration.body && + functionDeclaration.body.kind === SyntaxKind.FunctionBlock && + forEach((functionDeclaration.body).statements, s => s.kind === SyntaxKind.FunctionDeclaration); + } + + function getItemsWorker(nodes: Node[], createItem: (n: Node) => ts.NavigationBarItem): ts.NavigationBarItem[] { + var items: ts.NavigationBarItem[] = []; + + var keyToItem: Map = {}; + + for (var i = 0, n = nodes.length; i < n; i++) { + var child = nodes[i]; + var item = createItem(child); + if (item !== undefined) { + if (item.text.length > 0) { + var key = item.text + "-" + item.kind; + + var itemWithSameName = keyToItem[key]; + if (itemWithSameName) { + // We had an item with the same name. Merge these items together. + merge(itemWithSameName, item); + } + else { + keyToItem[key] = item; + items.push(item); + } + } + } + } + + return items; + } + + function merge(target: ts.NavigationBarItem, source: ts.NavigationBarItem) { + // First, add any spans in the source to the target. + target.spans.push.apply(target.spans, source.spans); + + if (source.childItems) { + if (!target.childItems) { + target.childItems = []; + } + + // Next, recursively merge or add any children in the source as appropriate. + outer: + for (var i = 0, n = source.childItems.length; i < n; i++) { + var sourceChild = source.childItems[i]; + + for (var j = 0, m = target.childItems.length; j < m; j++) { + var targetChild = target.childItems[j]; + + if (targetChild.text === sourceChild.text && targetChild.kind === sourceChild.kind) { + // Found a match. merge them. + merge(targetChild, sourceChild); + continue outer; + } + } + + // Didn't find a match, just add this child to the list. + target.childItems.push(sourceChild); + } + } + } + + function createChildItem(node: Node): ts.NavigationBarItem { + switch (node.kind) { + case SyntaxKind.Parameter: + var parameter = node; + if ((node.flags & NodeFlags.Modifier) === 0) { + return undefined; + } + + return createItem(node, getTextOfNode(parameter.name), ts.ScriptElementKind.memberVariableElement); + + case SyntaxKind.Method: + var method = node; + return createItem(node, getTextOfNode(method.name), ts.ScriptElementKind.memberFunctionElement); + + case SyntaxKind.GetAccessor: + var getAccessor = node; + return createItem(node, getTextOfNode(getAccessor.name), ts.ScriptElementKind.memberGetAccessorElement); + + case SyntaxKind.SetAccessor: + var setAccessor = node; + return createItem(node, getTextOfNode(setAccessor.name), ts.ScriptElementKind.memberSetAccessorElement); + + case SyntaxKind.IndexSignature: + return createItem(node, "[]", ts.ScriptElementKind.indexSignatureElement); + + case SyntaxKind.EnumMember: + var enumMember = node; + return createItem(node, getTextOfNode(enumMember.name), ts.ScriptElementKind.memberVariableElement); + + case SyntaxKind.CallSignature: + return createItem(node, "()", ts.ScriptElementKind.callSignatureElement); + + case SyntaxKind.ConstructSignature: + return createItem(node, "new()", ts.ScriptElementKind.constructSignatureElement); + + case SyntaxKind.Property: + var property = node; + return createItem(node, getTextOfNode(property.name), ts.ScriptElementKind.memberVariableElement); + + case SyntaxKind.FunctionDeclaration: + var functionDeclaration = node; + if (!isTopLevelFunctionDeclaration(functionDeclaration)) { + return createItem(node, getTextOfNode(functionDeclaration.name), ts.ScriptElementKind.functionElement); + } + break; + + case SyntaxKind.VariableDeclaration: + var variableDeclaration = node; + return createItem(node, getTextOfNode(variableDeclaration.name), ts.ScriptElementKind.variableElement); + + case SyntaxKind.Constructor: + return createItem(node, "constructor", ts.ScriptElementKind.constructorImplementationElement); + } + + return undefined; + + function createItem(node: Node, name: string, scriptElementKind: string): NavigationBarItem { + return getNavigationBarItem(name, scriptElementKind, getNodeModifiers(node), [getNodeSpan(node)]); + } + } + + function getNavigationBarItem(text: string, kind: string, kindModifiers: string, spans: TypeScript.TextSpan[], childItems: ts.NavigationBarItem[] = [], indent: number = 0): ts.NavigationBarItem { + return { + text: text, + kind: kind, + kindModifiers: kindModifiers, + spans: spans, + childItems: childItems, + indent: indent, + bolded: false, + grayed: false + }; + } + + function createTopLevelItem(node: Node): ts.NavigationBarItem { + switch (node.kind) { + case SyntaxKind.SourceFile: + return createSourceFileItem(node); + + case SyntaxKind.ClassDeclaration: + return createClassItem(node); + + case SyntaxKind.EnumDeclaration: + return createEnumItem(node); + + case SyntaxKind.InterfaceDeclaration: + return createIterfaceItem(node); + + case SyntaxKind.ModuleDeclaration: + return createModuleItem(node); + + case SyntaxKind.FunctionDeclaration: + return createFunctionItem(node); + } + + return undefined; + + function getModuleName(moduleDeclaration: ModuleDeclaration): string { + // We want to maintain quotation marks. + if (moduleDeclaration.name.kind === SyntaxKind.StringLiteral) { + return getTextOfNode(moduleDeclaration.name); + } + + // Otherwise, we need to aggregate each identifier to build up the qualified name. + var result: string[] = []; + + result.push(moduleDeclaration.name.text); + + while (moduleDeclaration.body && moduleDeclaration.body.kind === SyntaxKind.ModuleDeclaration) { + moduleDeclaration = moduleDeclaration.body; + + result.push(moduleDeclaration.name.text); + } + + return result.join("."); + } + + function createModuleItem(node: ModuleDeclaration): NavigationBarItem { + var moduleName = getModuleName(node); + + var childItems = getItemsWorker(getChildNodes((getInnermostModule(node).body).statements), createChildItem); + + return getNavigationBarItem(moduleName, + ts.ScriptElementKind.moduleElement, + getNodeModifiers(node), + [getNodeSpan(node)], + childItems, + getIndent(node)); + } + + function createFunctionItem(node: FunctionDeclaration) { + if (node.name && node.body && node.body.kind === SyntaxKind.FunctionBlock) { + var childItems = getItemsWorker((node.body).statements, createChildItem); + + return getNavigationBarItem(node.name.text, + ts.ScriptElementKind.functionElement, + getNodeModifiers(node), + [getNodeSpan(node)], + childItems, + getIndent(node)); + } + + return undefined; + } + + function createSourceFileItem(node: SourceFile): ts.NavigationBarItem { + var childItems = getItemsWorker(getChildNodes(node.statements), createChildItem); + + if (childItems === undefined || childItems.length === 0) { + return undefined; + } + + hasGlobalNode = true; + var rootName = isExternalModule(node) ? + "\"" + escapeString(getBaseFilename(removeFileExtension(normalizePath(node.filename)))) + "\"" : + "" + + return getNavigationBarItem(rootName, + ts.ScriptElementKind.moduleElement, + ts.ScriptElementKindModifier.none, + [getNodeSpan(node)], + childItems); + } + + function createClassItem(node: ClassDeclaration): ts.NavigationBarItem { + var childItems: NavigationBarItem[]; + + if (node.members) { + var constructor = forEach(node.members, member => { + return member.kind === SyntaxKind.Constructor && member; + }); + + // Add the constructor parameters in as children of the class (for property parameters). + var nodes: Node[] = constructor + ? constructor.parameters.concat(node.members) + : node.members; + + var childItems = getItemsWorker(nodes, createChildItem); + } + + return getNavigationBarItem( + node.name.text, + ts.ScriptElementKind.classElement, + getNodeModifiers(node), + [getNodeSpan(node)], + childItems, + getIndent(node)); + } + + function createEnumItem(node: EnumDeclaration): ts.NavigationBarItem { + var childItems = getItemsWorker(node.members, createChildItem); + return getNavigationBarItem( + node.name.text, + ts.ScriptElementKind.enumElement, + getNodeModifiers(node), + [getNodeSpan(node)], + childItems, + getIndent(node)); + } + + function createIterfaceItem(node: InterfaceDeclaration): ts.NavigationBarItem { + var childItems = getItemsWorker(node.members, createChildItem); + return getNavigationBarItem( + node.name.text, + ts.ScriptElementKind.interfaceElement, + getNodeModifiers(node), + [getNodeSpan(node)], + childItems, + getIndent(node)); + } + } + + function getInnermostModule(node: ModuleDeclaration): ModuleDeclaration { + while (node.body.kind === SyntaxKind.ModuleDeclaration) { + node = node.body; + } + + return node; + } + + function getNodeSpan(node: Node) { + return TypeScript.TextSpan.fromBounds(node.getStart(), node.getEnd()); + } + + function getTextOfNode(node: Node): string { + return getTextOfNodeFromSourceText(sourceFile.text, node); + } + } +} \ No newline at end of file diff --git a/src/services/services.ts b/src/services/services.ts index 33bdd4956ec..6e49e8427e5 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -6,7 +6,7 @@ /// /// -/// +/// /// /// /// @@ -1519,6 +1519,20 @@ module ts { } /// Helpers + export function getNodeModifiers(node: Node): string { + var flags = node.flags; + var result: string[] = []; + + if (flags & NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); + if (flags & NodeFlags.Protected) result.push(ScriptElementKindModifier.protectedMemberModifier); + if (flags & NodeFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier); + if (flags & NodeFlags.Static) result.push(ScriptElementKindModifier.staticModifier); + if (flags & NodeFlags.Export) result.push(ScriptElementKindModifier.exportedModifier); + if (isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier); + + return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none; + } + function getTargetLabel(referenceNode: Node, labelName: string): Identifier { while (referenceNode) { if (referenceNode.kind === SyntaxKind.LabeledStatement && (referenceNode).label.text === labelName) { @@ -2355,20 +2369,6 @@ module ts { : ScriptElementKindModifier.none; } - function getNodeModifiers(node: Node): string { - var flags = node.flags; - var result: string[] = []; - - if (flags & NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); - if (flags & NodeFlags.Protected) result.push(ScriptElementKindModifier.protectedMemberModifier); - if (flags & NodeFlags.Public) result.push(ScriptElementKindModifier.publicMemberModifier); - if (flags & NodeFlags.Static) result.push(ScriptElementKindModifier.staticModifier); - if (flags & NodeFlags.Export) result.push(ScriptElementKindModifier.exportedModifier); - if (isInAmbientContext(node)) result.push(ScriptElementKindModifier.ambientModifier); - - return result.length > 0 ? result.join(',') : ScriptElementKindModifier.none; - } - function getQuickInfoAtPosition(fileName: string, position: number): QuickInfo { synchronizeHostData(); @@ -4088,10 +4088,10 @@ module ts { return TypeScript.Services.Breakpoints.getBreakpointLocation(syntaxtree, position); } - function getNavigationBarItems(filename: string) { + function getNavigationBarItems(filename: string): NavigationBarItem[] { filename = TypeScript.switchToForwardSlashes(filename); - var syntaxTree = getSyntaxTree(filename); - return new TypeScript.Services.NavigationBarItemGetter().getItems(syntaxTree.sourceUnit()); + + return NavigationBar.getNavigationBarItems(getCurrentSourceFile(filename)); } function getSemanticClassifications(fileName: string, span: TypeScript.TextSpan): ClassifiedSpan[] { diff --git a/tests/baselines/reference/parserEqualsGreaterThanAfterFunction1.errors.txt b/tests/baselines/reference/parserEqualsGreaterThanAfterFunction1.errors.txt index 9a5039cc65c..7fe14c2be3b 100644 --- a/tests/baselines/reference/parserEqualsGreaterThanAfterFunction1.errors.txt +++ b/tests/baselines/reference/parserEqualsGreaterThanAfterFunction1.errors.txt @@ -1,10 +1,7 @@ tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEqualsGreaterThanAfterFunction1.ts(1,10): error TS1003: Identifier expected. -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEqualsGreaterThanAfterFunction1.ts(1,9): error TS2391: Function implementation is missing or not immediately following the declaration. -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEqualsGreaterThanAfterFunction1.ts (2 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEqualsGreaterThanAfterFunction1.ts (1 errors) ==== function => ~~ -!!! error TS1003: Identifier expected. - -!!! error TS2391: Function implementation is missing or not immediately following the declaration. \ No newline at end of file +!!! error TS1003: Identifier expected. \ No newline at end of file diff --git a/tests/baselines/reference/parserEqualsGreaterThanAfterFunction2.errors.txt b/tests/baselines/reference/parserEqualsGreaterThanAfterFunction2.errors.txt index 7705db0912e..cf56870d14d 100644 --- a/tests/baselines/reference/parserEqualsGreaterThanAfterFunction2.errors.txt +++ b/tests/baselines/reference/parserEqualsGreaterThanAfterFunction2.errors.txt @@ -2,10 +2,9 @@ tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEqualsGreaterThan tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEqualsGreaterThanAfterFunction2.ts(1,13): error TS1005: ',' expected. tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEqualsGreaterThanAfterFunction2.ts(1,17): error TS1005: ',' expected. tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEqualsGreaterThanAfterFunction2.ts(1,18): error TS1005: ')' expected. -tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEqualsGreaterThanAfterFunction2.ts(1,9): error TS2391: Function implementation is missing or not immediately following the declaration. -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEqualsGreaterThanAfterFunction2.ts (5 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEqualsGreaterThanAfterFunction2.ts (4 errors) ==== function (a => b; ~ !!! error TS1003: Identifier expected. @@ -14,6 +13,4 @@ tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEqualsGreaterThan ~ !!! error TS1005: ',' expected. -!!! error TS1005: ')' expected. - -!!! error TS2391: Function implementation is missing or not immediately following the declaration. \ No newline at end of file +!!! error TS1005: ')' expected. \ No newline at end of file diff --git a/tests/cases/fourslash/navbar_contains-no-duplicates.ts b/tests/cases/fourslash/navbar_contains-no-duplicates.ts index 4334d30229f..49d570ed770 100644 --- a/tests/cases/fourslash/navbar_contains-no-duplicates.ts +++ b/tests/cases/fourslash/navbar_contains-no-duplicates.ts @@ -27,7 +27,6 @@ //// export var {| "itemName": "x", "kind": "var" |}x = 3; //// } -verify.getScriptLexicalStructureListCount(12); test.markers().forEach(marker => { if (marker.data) { verify.getScriptLexicalStructureListContains( @@ -39,3 +38,4 @@ test.markers().forEach(marker => { marker.position); } }); +verify.getScriptLexicalStructureListCount(12); \ No newline at end of file diff --git a/tests/cases/fourslash/scriptLexicalStructureFunctions.ts b/tests/cases/fourslash/scriptLexicalStructureFunctions.ts new file mode 100644 index 00000000000..a42a226c2c0 --- /dev/null +++ b/tests/cases/fourslash/scriptLexicalStructureFunctions.ts @@ -0,0 +1,23 @@ +/// + +////{| "itemName": "", "kind": "module" |} +//// +////{| "itemName": "foo", "kind": "function" |}function foo() { +//// var x = 10; +//// {| "itemName": "bar", "kind": "function", "parentName": "foo" |}function bar() { +//// var y = 10; +//// {| "itemName": "biz", "kind": "function", "parentName": "bar" |}function biz() { +//// var z = 10; +//// } +//// } +////} +//// +////{| "itemName": "baz", "kind": "function", "parentName": "" |}function baz() { +//// var v = 10; +////} + +test.markers().forEach((marker) => { + verify.getScriptLexicalStructureListContains(marker.data.itemName, marker.data.kind, marker.fileName, marker.data.parentName); +}); + +verify.getScriptLexicalStructureListCount(5); // 4 functions + global diff --git a/tests/cases/fourslash/scriptLexicalStructureFunctionsBroken.ts b/tests/cases/fourslash/scriptLexicalStructureFunctionsBroken.ts new file mode 100644 index 00000000000..687b9b87296 --- /dev/null +++ b/tests/cases/fourslash/scriptLexicalStructureFunctionsBroken.ts @@ -0,0 +1,12 @@ +/// + +////{| "itemName": "f", "kind": "function" |} +////function f() { +//// function; +////} + +test.markers().forEach((marker) => { + verify.getScriptLexicalStructureListContains(marker.data.itemName, marker.data.kind, marker.fileName, marker.data.parentName); +}); + +verify.getScriptLexicalStructureListCount(1); // 1 function - no global since the inner function thinks it has a declaration. diff --git a/tests/cases/fourslash/scriptLexicalStructureFunctionsBroken2.ts b/tests/cases/fourslash/scriptLexicalStructureFunctionsBroken2.ts new file mode 100644 index 00000000000..1ac7ed09ad8 --- /dev/null +++ b/tests/cases/fourslash/scriptLexicalStructureFunctionsBroken2.ts @@ -0,0 +1,13 @@ +/// + +////function; +////{| "itemName": "f", "kind": "function" |} +////function f() { +//// function; +////} + +test.markers().forEach((marker) => { + verify.getScriptLexicalStructureListContains(marker.data.itemName, marker.data.kind, marker.fileName, marker.data.parentName); +}); + +verify.getScriptLexicalStructureListCount(1); // 1 function with no global - the broken declaration adds nothing for us at the global scope. diff --git a/tests/cases/fourslash/scriptLexicalStructureItems.ts b/tests/cases/fourslash/scriptLexicalStructureItems.ts index 025fd223fb9..e18f49c1db9 100644 --- a/tests/cases/fourslash/scriptLexicalStructureItems.ts +++ b/tests/cases/fourslash/scriptLexicalStructureItems.ts @@ -49,3 +49,4 @@ test.markers().forEach((marker) => { } }); +verify.getScriptLexicalStructureListCount(23); diff --git a/tests/cases/fourslash_old/scriptLexicalStructureItemsContainsNoAnonymouseFunctions.ts b/tests/cases/fourslash/scriptLexicalStructureItemsContainsNoAnonymousFunctions.ts similarity index 95% rename from tests/cases/fourslash_old/scriptLexicalStructureItemsContainsNoAnonymouseFunctions.ts rename to tests/cases/fourslash/scriptLexicalStructureItemsContainsNoAnonymousFunctions.ts index 2c8ef5825db..531575d6d10 100644 --- a/tests/cases/fourslash_old/scriptLexicalStructureItemsContainsNoAnonymouseFunctions.ts +++ b/tests/cases/fourslash/scriptLexicalStructureItemsContainsNoAnonymousFunctions.ts @@ -28,7 +28,7 @@ ////} ////function bar() { ////} -debugger; + goTo.marker("file1"); verify.getScriptLexicalStructureListCount(0); diff --git a/tests/cases/fourslash/scriptLexicalStructureItemsExternalModules.ts b/tests/cases/fourslash/scriptLexicalStructureItemsExternalModules.ts index dd8f64d87a2..550f1aed783 100644 --- a/tests/cases/fourslash/scriptLexicalStructureItemsExternalModules.ts +++ b/tests/cases/fourslash/scriptLexicalStructureItemsExternalModules.ts @@ -4,8 +4,8 @@ //// {| "itemName": "s", "kind": "property", "parentName": "Bar" |}public s: string; ////} -verify.getScriptLexicalStructureListCount(2); // external module node + class + property - test.markers().forEach((marker) => { verify.getScriptLexicalStructureListContains(marker.data.itemName, marker.data.kind, marker.fileName, marker.data.parentName); }); + +verify.getScriptLexicalStructureListCount(2); // external module node + class + property diff --git a/tests/cases/fourslash/scriptLexicalStructureItemsExternalModules2.ts b/tests/cases/fourslash/scriptLexicalStructureItemsExternalModules2.ts new file mode 100644 index 00000000000..b0bf6eb3fa2 --- /dev/null +++ b/tests/cases/fourslash/scriptLexicalStructureItemsExternalModules2.ts @@ -0,0 +1,15 @@ +/// + +// @Filename: test/file.ts +////{| "itemName": "Bar", "kind": "class" |}export class Bar { +//// {| "itemName": "s", "kind": "property", "parentName": "Bar" |}public s: string; +////} +////{| "itemName": "\"file\"", "kind": "module" |} +////{| "itemName": "x", "kind": "var", "parentName": "\"file\"" |} +////export var x: number; + +test.markers().forEach((marker) => { + verify.getScriptLexicalStructureListContains(marker.data.itemName, marker.data.kind, marker.fileName, marker.data.parentName); +}); + +verify.getScriptLexicalStructureListCount(4); // external module node + variable in module + class + property diff --git a/tests/cases/fourslash/scriptLexicalStructureItemsExternalModules3.ts b/tests/cases/fourslash/scriptLexicalStructureItemsExternalModules3.ts new file mode 100644 index 00000000000..9ef49e38776 --- /dev/null +++ b/tests/cases/fourslash/scriptLexicalStructureItemsExternalModules3.ts @@ -0,0 +1,15 @@ +/// + +// @Filename: test/my fil"e.ts +////{| "itemName": "Bar", "kind": "class" |}export class Bar { +//// {| "itemName": "s", "kind": "property", "parentName": "Bar" |}public s: string; +////} +////{| "itemName": "\"my fil\\\"e\"", "kind": "module" |} +////{| "itemName": "x", "kind": "var", "parentName": "\"file\"" |} +////export var x: number; + +test.markers().forEach((marker) => { + verify.getScriptLexicalStructureListContains(marker.data.itemName, marker.data.kind, marker.fileName, marker.data.parentName); +}); + +verify.getScriptLexicalStructureListCount(4); // external module node + variable in module + class + property diff --git a/tests/cases/fourslash_old/scriptLexicalStructureItemsModuleVariables.ts b/tests/cases/fourslash/scriptLexicalStructureItemsModuleVariables.ts similarity index 100% rename from tests/cases/fourslash_old/scriptLexicalStructureItemsModuleVariables.ts rename to tests/cases/fourslash/scriptLexicalStructureItemsModuleVariables.ts diff --git a/tests/cases/fourslash/scriptLexicalStructureModules.ts b/tests/cases/fourslash/scriptLexicalStructureModules.ts new file mode 100644 index 00000000000..ee0f91cc73c --- /dev/null +++ b/tests/cases/fourslash/scriptLexicalStructureModules.ts @@ -0,0 +1,48 @@ + +////{| "itemName": "\"X.Y.Z\"", "kind": "module" |} +////declare module "X.Y.Z" { +////} +//// +////{| "itemName": "'X2.Y2.Z2'", "kind": "module" |} +////declare module 'X2.Y2.Z2' { +////} +//// +////{| "itemName": "A.B.C", "kind": "module" |} +////module A.B.C { +//// {| "itemName": "x", "kind": "var", "parentName": "A.B.C" |} +//// export var x; +////} +//// +////{| "itemName": "A.B", "kind": "module" |} +////module A.B { +//// {| "itemName": "y", "kind": "var", "parentName": "A.B" |} +//// export var y; +////} +//// +////{| "itemName": "A", "kind": "module" |} +////module A { +//// {| "itemName": "z", "kind": "var", "parentName": "A" |} +//// export var z; +////} +//// +////{| "itemName": "A", "kind": "module" |} +////module A { +//// {| "itemName": "B", "kind": "module", "parentName": "E" |} +//// module B { +//// {| "itemName": "C", "kind": "module", "parentName": "F" |} +//// module C { +//// {| "itemName": "x", "kind": "var", "parentName": "C" |} +//// declare var x; +//// } +//// } +////} + + +test.markers().forEach((marker) => { + verify.getScriptLexicalStructureListContains(marker.data.itemName, marker.data.kind, marker.fileName, marker.data.parentName); +}); + +/// 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.getScriptLexicalStructureListCount(11); diff --git a/tests/cases/fourslash/scriptLexicalStructureMultilineStringIdentifiers.ts b/tests/cases/fourslash/scriptLexicalStructureMultilineStringIdentifiers.ts new file mode 100644 index 00000000000..796a4caa2d8 --- /dev/null +++ b/tests/cases/fourslash/scriptLexicalStructureMultilineStringIdentifiers.ts @@ -0,0 +1,41 @@ + +////{| "itemName": "\"Multiline\\r\\nMadness\"", "kind": "module" |} +////declare module "Multiline\r\nMadness" { +////} +//// +////{| "itemName": "\"Multiline\\\nMadness\"", "kind": "module" |} +////declare module "Multiline\ +////Madness" { +////} +////{| "itemName": "\"MultilineMadness\"", "kind": "module" |} +////declare module "MultilineMadness" {} +//// +////{| "itemName": "Foo", "kind": "interface" |} +////interface Foo { +//// {| "itemName": "\"a1\\\\\\r\\nb\"", "kind": "property", "parentName": "Foo" |} +//// "a1\\\r\nb"; +//// {| "itemName": "\"a2\\\n \\\n b\"", "kind": "method", "parentName": "Foo" |} +//// "a2\ +//// \ +//// b"(): Foo; +////} +//// +////{| "itemName": "Bar", "kind": "class" |} +////class Bar implements Foo { +//// {| "itemName": "'a1\\\\\\r\\nb'", "kind": "property", "parentName": "Bar" |} +//// 'a1\\\r\nb': Foo; +//// +//// {| "itemName": "'a2\\\n \\\n b'", "kind": "method", "parentName": "Bar" |} +//// 'a2\ +//// \ +//// b'(): Foo { +//// return this; +//// } +////} + + +test.markers().forEach((marker) => { + verify.getScriptLexicalStructureListContains(marker.data.itemName, marker.data.kind, marker.fileName, marker.data.parentName); +}); + +verify.getScriptLexicalStructureListCount(9); // interface w/ 2 properties, class w/ 2 properties, 3 modules \ No newline at end of file