From d6888b2834f37f880822c40953149d5d9b57550f Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 16 Sep 2014 15:30:19 -0700 Subject: [PATCH 01/21] Moved nav bar functionality into more 'functional' style. --- .../getScriptLexicalStructureWalker.ts | 269 +++++++++--------- src/services/services.ts | 6 +- 2 files changed, 137 insertions(+), 138 deletions(-) diff --git a/src/services/getScriptLexicalStructureWalker.ts b/src/services/getScriptLexicalStructureWalker.ts index bfce8e0067c..f30810ee2f4 100644 --- a/src/services/getScriptLexicalStructureWalker.ts +++ b/src/services/getScriptLexicalStructureWalker.ts @@ -1,15 +1,17 @@ /// module TypeScript.Services { - export class NavigationBarItemGetter { - private hasGlobalNode = false; + export function getNavigationBarItemsHelper(sourceUnit: TypeScript.SourceUnitSyntax): ts.NavigationBarItem[] { + var hasGlobalNode = false; - private getIndent(node: ISyntaxNode): number { - var indent = this.hasGlobalNode ? 1 : 0; + return getItemsWorker(getTopLevelNodes(sourceUnit), createTopLevelItem); + + function getIndent(node: ISyntaxNode): number { + var indent = hasGlobalNode ? 1 : 0; var current = node.parent; - while (current != null) { - if (current.kind() == SyntaxKind.ModuleDeclaration || current.kind() === SyntaxKind.FunctionDeclaration) { + while (current) { + if (current.kind() === SyntaxKind.ModuleDeclaration || current.kind() === SyntaxKind.FunctionDeclaration) { indent++; } @@ -19,7 +21,7 @@ module TypeScript.Services { return indent; } - private getKindModifiers(modifiers: TypeScript.ISyntaxToken[]): string { + function getKindModifiers(modifiers: TypeScript.ISyntaxToken[]): string { var result: string[] = []; for (var i = 0, n = modifiers.length; i < n; i++) { @@ -29,11 +31,7 @@ module TypeScript.Services { 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[] { + function getChildNodes(nodes: IModuleElementSyntax[]): ISyntaxNode[] { var childNodes: ISyntaxNode[] = []; for (var i = 0, n = nodes.length; i < n; i++) { @@ -51,16 +49,16 @@ module TypeScript.Services { return childNodes; } - private getTopLevelNodes(node: SourceUnitSyntax): ISyntaxNode[] { + function getTopLevelNodes(node: SourceUnitSyntax): ISyntaxNode[] { var topLevelNodes: ISyntaxNode[] = []; topLevelNodes.push(node); - this.addTopLevelNodes(node.moduleElements, topLevelNodes); + addTopLevelNodes(node.moduleElements, topLevelNodes); return topLevelNodes; } - private addTopLevelNodes(nodes: IModuleElementSyntax[], topLevelNodes: ISyntaxNode[]): void { + function addTopLevelNodes(nodes: IModuleElementSyntax[], topLevelNodes: ISyntaxNode[]): void { for (var i = 0, n = nodes.length; i < n; i++) { var node = nodes[i]; switch (node.kind()) { @@ -73,43 +71,42 @@ module TypeScript.Services { case SyntaxKind.ModuleDeclaration: var moduleDeclaration = node; topLevelNodes.push(node); - this.addTopLevelNodes(moduleDeclaration.moduleElements, topLevelNodes); + addTopLevelNodes(moduleDeclaration.moduleElements, topLevelNodes); break; case SyntaxKind.FunctionDeclaration: var functionDeclaration = node; - if (this.isTopLevelFunctionDeclaration(functionDeclaration)) { + if (isTopLevelFunctionDeclaration(functionDeclaration)) { topLevelNodes.push(node); - this.addTopLevelNodes(functionDeclaration.block.statements, topLevelNodes); + addTopLevelNodes(functionDeclaration.block.statements, topLevelNodes); } break; } } } - public isTopLevelFunctionDeclaration(functionDeclaration: FunctionDeclarationSyntax) { + function 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[] { + function getItemsWorker(nodes: 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 !== 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. - this.merge(itemWithSameName, item); + merge(itemWithSameName, item); } else { keyToItem[key] = item; @@ -122,7 +119,7 @@ module TypeScript.Services { return items; } - private merge(target: ts.NavigationBarItem, source: ts.NavigationBarItem) { + 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); @@ -141,7 +138,7 @@ module TypeScript.Services { if (targetChild.text === sourceChild.text && targetChild.kind === sourceChild.kind) { // Found a match. merge them. - this.merge(targetChild, sourceChild); + merge(targetChild, sourceChild); continue outer; } } @@ -152,26 +149,26 @@ module TypeScript.Services { } } - private createChildItem(node: ISyntaxNode): ts.NavigationBarItem { + function createChildItem(node: ISyntaxNode): ts.NavigationBarItem { switch (node.kind()) { case SyntaxKind.Parameter: var parameter = node; if (parameter.modifiers.length === 0) { - return null; + return undefined; } - return new ts.NavigationBarItem(parameter.identifier.text(), ts.ScriptElementKind.memberVariableElement, this.getKindModifiers(parameter.modifiers), [TextSpan.fromBounds(start(node), end(node))]); + return new ts.NavigationBarItem(parameter.identifier.text(), ts.ScriptElementKind.memberVariableElement, getKindModifiers(parameter.modifiers), [TextSpan.fromBounds(start(node), end(node))]); case SyntaxKind.MemberFunctionDeclaration: var memberFunction = node; - return new ts.NavigationBarItem(memberFunction.propertyName.text(), ts.ScriptElementKind.memberFunctionElement, this.getKindModifiers(memberFunction.modifiers), [TextSpan.fromBounds(start(node), end(node))]); + return new ts.NavigationBarItem(memberFunction.propertyName.text(), ts.ScriptElementKind.memberFunctionElement, getKindModifiers(memberFunction.modifiers), [TextSpan.fromBounds(start(node), end(node))]); case SyntaxKind.GetAccessor: var getAccessor = node; - return new ts.NavigationBarItem(getAccessor.propertyName.text(), ts.ScriptElementKind.memberGetAccessorElement, this.getKindModifiers(getAccessor.modifiers), [TextSpan.fromBounds(start(node), end(node))]); + return new ts.NavigationBarItem(getAccessor.propertyName.text(), ts.ScriptElementKind.memberGetAccessorElement, getKindModifiers(getAccessor.modifiers), [TextSpan.fromBounds(start(node), end(node))]); case SyntaxKind.SetAccessor: var setAccessor = node; - return new ts.NavigationBarItem(setAccessor.propertyName.text(), ts.ScriptElementKind.memberSetAccessorElement, this.getKindModifiers(setAccessor.modifiers), [TextSpan.fromBounds(start(node), end(node))]); + return new ts.NavigationBarItem(setAccessor.propertyName.text(), ts.ScriptElementKind.memberSetAccessorElement, getKindModifiers(setAccessor.modifiers), [TextSpan.fromBounds(start(node), end(node))]); case SyntaxKind.IndexSignature: var indexSignature = node; @@ -199,14 +196,14 @@ module TypeScript.Services { case SyntaxKind.FunctionDeclaration: var functionDeclaration = node; - if (!this.isTopLevelFunctionDeclaration(functionDeclaration)) { - return new ts.NavigationBarItem(functionDeclaration.identifier.text(), ts.ScriptElementKind.functionElement, this.getKindModifiers(functionDeclaration.modifiers), [TextSpan.fromBounds(start(node), end(node))]); + if (!isTopLevelFunctionDeclaration(functionDeclaration)) { + return new ts.NavigationBarItem(functionDeclaration.identifier.text(), ts.ScriptElementKind.functionElement, getKindModifiers(functionDeclaration.modifiers), [TextSpan.fromBounds(start(node), end(node))]); } break; case SyntaxKind.MemberVariableDeclaration: var memberVariableDeclaration = node; - return new ts.NavigationBarItem(memberVariableDeclaration.variableDeclarator.propertyName.text(), ts.ScriptElementKind.memberVariableElement, this.getKindModifiers(memberVariableDeclaration.modifiers), [TextSpan.fromBounds(start(memberVariableDeclaration.variableDeclarator), end(memberVariableDeclaration.variableDeclarator))]); + return new ts.NavigationBarItem(memberVariableDeclaration.variableDeclarator.propertyName.text(), ts.ScriptElementKind.memberVariableElement, getKindModifiers(memberVariableDeclaration.modifiers), [TextSpan.fromBounds(start(memberVariableDeclaration.variableDeclarator), end(memberVariableDeclaration.variableDeclarator))]); case SyntaxKind.VariableDeclarator: var variableDeclarator = node; @@ -217,135 +214,135 @@ module TypeScript.Services { return new ts.NavigationBarItem("constructor", ts.ScriptElementKind.constructorImplementationElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]); } - return null; + return undefined; } - private createTopLevelItem(node: ISyntaxNode): ts.NavigationBarItem { + function createTopLevelItem(node: ISyntaxNode): ts.NavigationBarItem { switch (node.kind()) { case SyntaxKind.SourceUnit: - return this.createSourceUnitItem(node); + return createSourceUnitItem(node); case SyntaxKind.ClassDeclaration: - return this.createClassItem(node); + return createClassItem(node); case SyntaxKind.EnumDeclaration: - return this.createEnumItem(node); + return createEnumItem(node); case SyntaxKind.InterfaceDeclaration: - return this.createIterfaceItem(node); + return createIterfaceItem(node); case SyntaxKind.ModuleDeclaration: - return this.createModuleItem(node); + return createModuleItem(node); case SyntaxKind.FunctionDeclaration: - return this.createFunctionItem(node); + return createFunctionItem(node); } - return null; - } + return undefined; - private getModuleNames(node: TypeScript.ModuleDeclarationSyntax): string[] { - var result: string[] = []; + function getModuleNames(node: TypeScript.ModuleDeclarationSyntax): string[] { + var result: string[] = []; - if (node.stringLiteral) { - result.push(node.stringLiteral.text()); - } - else { - this.getModuleNamesHelper(node.name, result); + if (node.stringLiteral) { + result.push(node.stringLiteral.text()); + } + else { + getModuleNamesHelper(node.name, result); + } + + return 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 new ts.NavigationBarItem(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 new ts.NavigationBarItem(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; + function getModuleNamesHelper(name: TypeScript.INameSyntax, result: string[]): void { + if (name.kind() === TypeScript.SyntaxKind.QualifiedName) { + var qualifiedName = name; + getModuleNamesHelper(qualifiedName.left, result); + result.push(qualifiedName.right.text()); + } + else { + result.push((name).text()); + } } - this.hasGlobalNode = true; - return new ts.NavigationBarItem("", - ts.ScriptElementKind.moduleElement, - ts.ScriptElementKindModifier.none, - [TextSpan.fromBounds(start(node), end(node))], - childItems); - } + function createModuleItem(node: ModuleDeclarationSyntax): ts.NavigationBarItem { + var moduleNames = getModuleNames(node); - private createClassItem(node: ClassDeclarationSyntax): ts.NavigationBarItem { - var constructor = ArrayUtilities.firstOrDefault( - node.classElements, n => n.kind() === SyntaxKind.ConstructorDeclaration); + var childItems = getItemsWorker(getChildNodes(node.moduleElements), n => createChildItem(n)); - // 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; + return new ts.NavigationBarItem(moduleNames.join("."), + ts.ScriptElementKind.moduleElement, + getKindModifiers(node.modifiers), + [TextSpan.fromBounds(start(node), end(node))], + childItems, + getIndent(node)); + } - var childItems = this.getItemsWorker(() => nodes, n => this.createChildItem(n)); - return new ts.NavigationBarItem( - node.identifier.text(), - ts.ScriptElementKind.classElement, - this.getKindModifiers(node.modifiers), - [TextSpan.fromBounds(start(node), end(node))], - childItems, - this.getIndent(node)); - } + function createFunctionItem(node: FunctionDeclarationSyntax) { + var childItems = getItemsWorker(node.block.statements, n => createChildItem(n)); - private createEnumItem(node: TypeScript.EnumDeclarationSyntax): ts.NavigationBarItem { - var childItems = this.getItemsWorker(() => node.enumElements, n => this.createChildItem(n)); - return new ts.NavigationBarItem( - node.identifier.text(), - ts.ScriptElementKind.enumElement, - this.getKindModifiers(node.modifiers), - [TextSpan.fromBounds(start(node), end(node))], - childItems, - this.getIndent(node)); - } + return new ts.NavigationBarItem(node.identifier.text(), + ts.ScriptElementKind.functionElement, + getKindModifiers(node.modifiers), + [TextSpan.fromBounds(start(node), end(node))], + childItems, + getIndent(node)); + } - private createIterfaceItem(node: TypeScript.InterfaceDeclarationSyntax): ts.NavigationBarItem { - var childItems = this.getItemsWorker(() => node.body.typeMembers, n => this.createChildItem(n)); - return new ts.NavigationBarItem( - node.identifier.text(), - ts.ScriptElementKind.interfaceElement, - this.getKindModifiers(node.modifiers), - [TextSpan.fromBounds(start(node), end(node))], - childItems, - this.getIndent(node)); + function createSourceUnitItem(node: SourceUnitSyntax): ts.NavigationBarItem { + var childItems = getItemsWorker(getChildNodes(node.moduleElements), n => createChildItem(n)); + + if (childItems === undefined || childItems.length === 0) { + return undefined; + } + + hasGlobalNode = true; + return new ts.NavigationBarItem("", + ts.ScriptElementKind.moduleElement, + ts.ScriptElementKindModifier.none, + [TextSpan.fromBounds(start(node), end(node))], + childItems); + } + + function createClassItem(node: ClassDeclarationSyntax): ts.NavigationBarItem { + var constructor = ArrayUtilities.firstOrDefault( + node.classElements, n => n.kind() === SyntaxKind.ConstructorDeclaration); + + // Add the constructor parameters in as children of the class (for property parameters). + var nodes: ISyntaxNode[] = constructor + ? (constructor.callSignature.parameterList.parameters).concat(node.classElements) + : node.classElements; + + var childItems = getItemsWorker(nodes, n => createChildItem(n)); + return new ts.NavigationBarItem( + node.identifier.text(), + ts.ScriptElementKind.classElement, + getKindModifiers(node.modifiers), + [TextSpan.fromBounds(start(node), end(node))], + childItems, + getIndent(node)); + } + + function createEnumItem(node: TypeScript.EnumDeclarationSyntax): ts.NavigationBarItem { + var childItems = getItemsWorker(node.enumElements, n => createChildItem(n)); + return new ts.NavigationBarItem( + node.identifier.text(), + ts.ScriptElementKind.enumElement, + getKindModifiers(node.modifiers), + [TextSpan.fromBounds(start(node), end(node))], + childItems, + getIndent(node)); + } + + function createIterfaceItem(node: TypeScript.InterfaceDeclarationSyntax): ts.NavigationBarItem { + var childItems = getItemsWorker(node.body.typeMembers, n => createChildItem(n)); + return new ts.NavigationBarItem( + node.identifier.text(), + ts.ScriptElementKind.interfaceElement, + getKindModifiers(node.modifiers), + [TextSpan.fromBounds(start(node), end(node))], + childItems, + getIndent(node)); + } } } } \ No newline at end of file diff --git a/src/services/services.ts b/src/services/services.ts index d51eeee97c0..ed32721a1ac 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -3118,10 +3118,12 @@ 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 TypeScript.Services.getNavigationBarItemsHelper(syntaxTree.sourceUnit()); } function getOutliningSpans(filename: string): OutliningSpan[] { From e69b9e6362aeb8a8fa3cf1ae076e5b7618d26543 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 17 Sep 2014 15:28:41 -0700 Subject: [PATCH 02/21] Fixed issue where parser improperly parses a function declaration with no identifier. --- src/compiler/checker.ts | 4 ++++ src/compiler/parser.ts | 5 ++++- .../parserEqualsGreaterThanAfterFunction1.errors.txt | 6 ++---- .../parserEqualsGreaterThanAfterFunction2.errors.txt | 6 ++---- 4 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b99d6d27d20..db876da3b9f 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -5379,6 +5379,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/parser.ts b/src/compiler/parser.ts index 25ca24ae61b..6fa2cdd244a 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -953,7 +953,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/tests/baselines/reference/parserEqualsGreaterThanAfterFunction1.errors.txt b/tests/baselines/reference/parserEqualsGreaterThanAfterFunction1.errors.txt index 9f428d7fea7..fd3e1c42779 100644 --- a/tests/baselines/reference/parserEqualsGreaterThanAfterFunction1.errors.txt +++ b/tests/baselines/reference/parserEqualsGreaterThanAfterFunction1.errors.txt @@ -1,6 +1,4 @@ -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEqualsGreaterThanAfterFunction1.ts (2 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEqualsGreaterThanAfterFunction1.ts (1 errors) ==== function => ~~ -!!! Identifier expected. - -!!! Function implementation is missing or not immediately following the declaration. \ No newline at end of file +!!! 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 4e9b5fbaa86..0d81cd7f35d 100644 --- a/tests/baselines/reference/parserEqualsGreaterThanAfterFunction2.errors.txt +++ b/tests/baselines/reference/parserEqualsGreaterThanAfterFunction2.errors.txt @@ -1,4 +1,4 @@ -==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEqualsGreaterThanAfterFunction2.ts (5 errors) ==== +==== tests/cases/conformance/parser/ecmascript5/ErrorRecovery/parserEqualsGreaterThanAfterFunction2.ts (4 errors) ==== function (a => b; ~ !!! Identifier expected. @@ -7,6 +7,4 @@ ~ !!! ',' expected. -!!! ')' expected. - -!!! Function implementation is missing or not immediately following the declaration. \ No newline at end of file +!!! ')' expected. \ No newline at end of file From 55e772cfe086e69c2336c17f89a745a903d942e9 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 17 Sep 2014 15:30:26 -0700 Subject: [PATCH 03/21] Re-added tests. --- .../scriptLexicalStructureItemsContainsNoAnonymouseFunctions.ts | 0 .../scriptLexicalStructureItemsModuleVariables.ts | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/cases/{fourslash_old => fourslash}/scriptLexicalStructureItemsContainsNoAnonymouseFunctions.ts (100%) rename tests/cases/{fourslash_old => fourslash}/scriptLexicalStructureItemsModuleVariables.ts (100%) diff --git a/tests/cases/fourslash_old/scriptLexicalStructureItemsContainsNoAnonymouseFunctions.ts b/tests/cases/fourslash/scriptLexicalStructureItemsContainsNoAnonymouseFunctions.ts similarity index 100% rename from tests/cases/fourslash_old/scriptLexicalStructureItemsContainsNoAnonymouseFunctions.ts rename to tests/cases/fourslash/scriptLexicalStructureItemsContainsNoAnonymouseFunctions.ts 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 From b285ef165bfe6f16994e610bb2dbde6ca0180c60 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 17 Sep 2014 17:40:32 -0700 Subject: [PATCH 04/21] Added fourslash tests. --- .../scriptLexicalStructureFunctions.ts | 23 ++++++++++ .../scriptLexicalStructureFunctionsBroken.ts | 12 +++++ .../scriptLexicalStructureFunctionsBroken2.ts | 13 ++++++ .../fourslash/scriptLexicalStructureItems.ts | 1 + ...iptLexicalStructureItemsExternalModules.ts | 4 +- .../scriptLexicalStructureModules.ts | 44 +++++++++++++++++++ 6 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 tests/cases/fourslash/scriptLexicalStructureFunctions.ts create mode 100644 tests/cases/fourslash/scriptLexicalStructureFunctionsBroken.ts create mode 100644 tests/cases/fourslash/scriptLexicalStructureFunctionsBroken2.ts create mode 100644 tests/cases/fourslash/scriptLexicalStructureModules.ts diff --git a/tests/cases/fourslash/scriptLexicalStructureFunctions.ts b/tests/cases/fourslash/scriptLexicalStructureFunctions.ts new file mode 100644 index 00000000000..7723bd0ee68 --- /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" |}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/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/scriptLexicalStructureModules.ts b/tests/cases/fourslash/scriptLexicalStructureModules.ts new file mode 100644 index 00000000000..c7446111a0a --- /dev/null +++ b/tests/cases/fourslash/scriptLexicalStructureModules.ts @@ -0,0 +1,44 @@ + +////{| "itemName": "\"X.Y.Z\"", "kind": "module" |} +////declare module "X.Y.Z" { +////} +//// +////{| "itemName": "A.B.C", "kind": "module" |} +////module A.B.C { +//// {| "itemName": "x", "kind": "var", "parent": "A.B.C" |} +//// export var x; +////} +//// +////{| "itemName": "A.B", "kind": "module" |} +////module A.B { +//// {| "itemName": "y", "kind": "var", "parent": "A.B" |} +//// export var y; +////} +//// +////{| "itemName": "A", "kind": "module" |} +////module A { +//// {| "itemName": "z", "kind": "var", "parent": "A" |} +//// export var z; +////} +//// +////{| "itemName": "A", "kind": "module" |} +////module A { +//// {| "itemName": "B", "kind": "module", "parent": "E" |} +//// module B { +//// {| "itemName": "C", "kind": "module", "parent": "F" |} +//// module C { +//// {| "itemName": "x", "kind": "var", "parent": "C" |} +//// declare var x; +//// } +//// } +////} + + +test.markers().forEach((marker) => { + verify.getScriptLexicalStructureListContains(marker.data.itemName, marker.data.kind, marker.fileName, marker.data.parentName); +}); + +/// We have 7 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 6 modules. +verify.getScriptLexicalStructureListCount(10); From a9e071c9604c3d397611eb956c15a93c77ead953 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 17 Sep 2014 17:52:57 -0700 Subject: [PATCH 05/21] Renamed file. --- ...=> scriptLexicalStructureItemsContainsNoAnonymousFunctions.ts} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/cases/fourslash/{scriptLexicalStructureItemsContainsNoAnonymouseFunctions.ts => scriptLexicalStructureItemsContainsNoAnonymousFunctions.ts} (100%) diff --git a/tests/cases/fourslash/scriptLexicalStructureItemsContainsNoAnonymouseFunctions.ts b/tests/cases/fourslash/scriptLexicalStructureItemsContainsNoAnonymousFunctions.ts similarity index 100% rename from tests/cases/fourslash/scriptLexicalStructureItemsContainsNoAnonymouseFunctions.ts rename to tests/cases/fourslash/scriptLexicalStructureItemsContainsNoAnonymousFunctions.ts From e3077e34b7532c582ed3859063663caad201b71d Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 17 Sep 2014 18:11:37 -0700 Subject: [PATCH 06/21] Amended test for quoted module names. --- tests/cases/fourslash/scriptLexicalStructureModules.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/cases/fourslash/scriptLexicalStructureModules.ts b/tests/cases/fourslash/scriptLexicalStructureModules.ts index c7446111a0a..4331e64e0b0 100644 --- a/tests/cases/fourslash/scriptLexicalStructureModules.ts +++ b/tests/cases/fourslash/scriptLexicalStructureModules.ts @@ -3,6 +3,10 @@ ////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", "parent": "A.B.C" |} @@ -38,7 +42,7 @@ test.markers().forEach((marker) => { verify.getScriptLexicalStructureListContains(marker.data.itemName, marker.data.kind, marker.fileName, marker.data.parentName); }); -/// We have 7 module keywords, and 4 var keywords. +/// 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 6 modules. -verify.getScriptLexicalStructureListCount(10); +/// The two 'A' modules, however, do get merged, so in reality we have 7 modules. +verify.getScriptLexicalStructureListCount(11); From ad12b8bf765decfebb5b818564ea274bda0f5f16 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 17 Sep 2014 18:12:16 -0700 Subject: [PATCH 07/21] Changed order of count check. --- tests/cases/fourslash/navbar_contains-no-duplicates.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 From be18ada22f2560fd0a2790a780fd89ba1095c66a Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Wed, 17 Sep 2014 18:13:06 -0700 Subject: [PATCH 08/21] Finally using new tree. --- .../getScriptLexicalStructureWalker.ts | 297 ++++++++++-------- src/services/services.ts | 4 +- 2 files changed, 159 insertions(+), 142 deletions(-) diff --git a/src/services/getScriptLexicalStructureWalker.ts b/src/services/getScriptLexicalStructureWalker.ts index f30810ee2f4..d65e1d4a48d 100644 --- a/src/services/getScriptLexicalStructureWalker.ts +++ b/src/services/getScriptLexicalStructureWalker.ts @@ -1,17 +1,17 @@ /// -module TypeScript.Services { - export function getNavigationBarItemsHelper(sourceUnit: TypeScript.SourceUnitSyntax): ts.NavigationBarItem[] { +module ts { + export function getNavigationBarItemsHelper(sourceFile: SourceFile): ts.NavigationBarItem[] { var hasGlobalNode = false; - return getItemsWorker(getTopLevelNodes(sourceUnit), createTopLevelItem); + return getItemsWorker(getTopLevelNodes(sourceFile), createTopLevelItem); - function getIndent(node: ISyntaxNode): number { + function getIndent(node: Node): number { var indent = hasGlobalNode ? 1 : 0; var current = node.parent; while (current) { - if (current.kind() === SyntaxKind.ModuleDeclaration || current.kind() === SyntaxKind.FunctionDeclaration) { + if (current.kind === SyntaxKind.ModuleDeclaration || current.kind === SyntaxKind.FunctionDeclaration) { indent++; } @@ -21,47 +21,38 @@ module TypeScript.Services { return indent; } - function 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; - } - - function getChildNodes(nodes: IModuleElementSyntax[]): ISyntaxNode[] { - var childNodes: ISyntaxNode[] = []; + function getChildNodes(nodes: Node[]): Node[] { + var childNodes: Node[] = []; for (var i = 0, n = nodes.length; i < n; i++) { - var node = nodes[i]; + var node = nodes[i]; - if (node.kind() === SyntaxKind.FunctionDeclaration) { + if (node.kind === SyntaxKind.FunctionDeclaration) { childNodes.push(node); } - else if (node.kind() === SyntaxKind.VariableStatement) { - var variableDeclaration = (node).variableDeclaration; - childNodes.push.apply(childNodes, variableDeclaration.variableDeclarators); + else if (node.kind === SyntaxKind.VariableStatement) { + forEach((node).declarations, declaration => { + childNodes.push(declaration); + }); } } return childNodes; } - function getTopLevelNodes(node: SourceUnitSyntax): ISyntaxNode[] { - var topLevelNodes: ISyntaxNode[] = []; + function getTopLevelNodes(node: SourceFile): Node[] { + var topLevelNodes: Node[] = []; topLevelNodes.push(node); - addTopLevelNodes(node.moduleElements, topLevelNodes); + addTopLevelNodes(node.statements, topLevelNodes); return topLevelNodes; } - function addTopLevelNodes(nodes: IModuleElementSyntax[], topLevelNodes: ISyntaxNode[]): void { + function addTopLevelNodes(nodes: Node[], topLevelNodes: Node[]): void { for (var i = 0, n = nodes.length; i < n; i++) { var node = nodes[i]; - switch (node.kind()) { + switch (node.kind) { case SyntaxKind.ClassDeclaration: case SyntaxKind.EnumDeclaration: case SyntaxKind.InterfaceDeclaration: @@ -69,32 +60,39 @@ module TypeScript.Services { break; case SyntaxKind.ModuleDeclaration: - var moduleDeclaration = node; + var moduleDeclaration = node; topLevelNodes.push(node); - addTopLevelNodes(moduleDeclaration.moduleElements, topLevelNodes); + addTopLevelNodes((getInnermostModule(moduleDeclaration).body).statements, topLevelNodes); break; case SyntaxKind.FunctionDeclaration: - var functionDeclaration = node; + var functionDeclaration = node; if (isTopLevelFunctionDeclaration(functionDeclaration)) { topLevelNodes.push(node); - addTopLevelNodes(functionDeclaration.block.statements, topLevelNodes); + addTopLevelNodes((functionDeclaration.body).statements, topLevelNodes); } break; } } } - function isTopLevelFunctionDeclaration(functionDeclaration: FunctionDeclarationSyntax) { + function isTopLevelFunctionDeclaration(functionDeclaration: FunctionDeclaration) { // 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); + return functionDeclaration.kind === SyntaxKind.FunctionDeclaration && + functionDeclaration.body && + functionDeclaration.body.kind === SyntaxKind.FunctionBlock && + forEach((functionDeclaration.body).statements, s => s.kind === SyntaxKind.FunctionDeclaration); } - function getItemsWorker(nodes: ISyntaxNode[], createItem: (n: ISyntaxNode) => ts.NavigationBarItem): ts.NavigationBarItem[] { + function getItemsWorker(nodes: Node[], createItem: (n: Node) => ts.NavigationBarItem): ts.NavigationBarItem[]{ var items: ts.NavigationBarItem[] = []; - var keyToItem = createIntrinsicsObject(); + if (!nodes) { + return items; + } + + var keyToItem: Map = {}; for (var i = 0, n = nodes.length; i < n; i++) { var child = nodes[i]; @@ -149,147 +147,135 @@ module TypeScript.Services { } } - function createChildItem(node: ISyntaxNode): ts.NavigationBarItem { - switch (node.kind()) { + function createChildItem(node: Node): ts.NavigationBarItem { + switch (node.kind) { case SyntaxKind.Parameter: - var parameter = node; - if (parameter.modifiers.length === 0) { + var parameter = node; + if ((node.flags & NodeFlags.Modifier) === 0) { return undefined; } - return new ts.NavigationBarItem(parameter.identifier.text(), ts.ScriptElementKind.memberVariableElement, getKindModifiers(parameter.modifiers), [TextSpan.fromBounds(start(node), end(node))]); + return new ts.NavigationBarItem(parameter.name.text, ts.ScriptElementKind.memberVariableElement, getNodeModifiers(node), [getNodeSpan(node)]); - case SyntaxKind.MemberFunctionDeclaration: - var memberFunction = node; - return new ts.NavigationBarItem(memberFunction.propertyName.text(), ts.ScriptElementKind.memberFunctionElement, getKindModifiers(memberFunction.modifiers), [TextSpan.fromBounds(start(node), end(node))]); + case SyntaxKind.Method: + var memberFunction = node; + return new ts.NavigationBarItem(memberFunction.name.text, ts.ScriptElementKind.memberFunctionElement, getNodeModifiers(node), [getNodeSpan(node)]); case SyntaxKind.GetAccessor: - var getAccessor = node; - return new ts.NavigationBarItem(getAccessor.propertyName.text(), ts.ScriptElementKind.memberGetAccessorElement, getKindModifiers(getAccessor.modifiers), [TextSpan.fromBounds(start(node), end(node))]); + var getAccessor = node; + return new ts.NavigationBarItem(getAccessor.name.text, ts.ScriptElementKind.memberGetAccessorElement, getNodeModifiers(node), [getNodeSpan(node)]); case SyntaxKind.SetAccessor: - var setAccessor = node; - return new ts.NavigationBarItem(setAccessor.propertyName.text(), ts.ScriptElementKind.memberSetAccessorElement, getKindModifiers(setAccessor.modifiers), [TextSpan.fromBounds(start(node), end(node))]); + var setAccessor = node; + return new ts.NavigationBarItem(setAccessor.name.text, ts.ScriptElementKind.memberSetAccessorElement, getNodeModifiers(node), [getNodeSpan(node)]); case SyntaxKind.IndexSignature: - var indexSignature = node; - return new ts.NavigationBarItem("[]", ts.ScriptElementKind.indexSignatureElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]); + return new ts.NavigationBarItem("[]", ts.ScriptElementKind.indexSignatureElement, ts.ScriptElementKindModifier.none, [getNodeSpan(node)]); - case SyntaxKind.EnumElement: - var enumElement = node; - return new ts.NavigationBarItem(enumElement.propertyName.text(), ts.ScriptElementKind.memberVariableElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]); + case SyntaxKind.EnumMember: + var enumElement = node; + return new ts.NavigationBarItem(enumElement.name.text, ts.ScriptElementKind.memberVariableElement, ts.ScriptElementKindModifier.none, [getNodeSpan(node)]); case SyntaxKind.CallSignature: - var callSignature = node; - return new ts.NavigationBarItem("()", ts.ScriptElementKind.callSignatureElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]); + return new ts.NavigationBarItem("()", ts.ScriptElementKind.callSignatureElement, ts.ScriptElementKindModifier.none, []); case SyntaxKind.ConstructSignature: - var constructSignature = node; - return new ts.NavigationBarItem("new()", ts.ScriptElementKind.constructSignatureElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]); + return new ts.NavigationBarItem("new()", ts.ScriptElementKind.constructSignatureElement, ts.ScriptElementKindModifier.none, [getNodeSpan(node)]); - case SyntaxKind.MethodSignature: - var methodSignature = node; - return new ts.NavigationBarItem(methodSignature.propertyName.text(), ts.ScriptElementKind.memberFunctionElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]); - - case SyntaxKind.PropertySignature: - var propertySignature = node; - return new ts.NavigationBarItem(propertySignature.propertyName.text(), ts.ScriptElementKind.memberVariableElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]); + case SyntaxKind.Property: + var propertySignature = node; + return new ts.NavigationBarItem(propertySignature.name.text, ts.ScriptElementKind.memberVariableElement, getNodeModifiers(node), [getNodeSpan(node)]); case SyntaxKind.FunctionDeclaration: - var functionDeclaration = node; + var functionDeclaration = node; if (!isTopLevelFunctionDeclaration(functionDeclaration)) { - return new ts.NavigationBarItem(functionDeclaration.identifier.text(), ts.ScriptElementKind.functionElement, getKindModifiers(functionDeclaration.modifiers), [TextSpan.fromBounds(start(node), end(node))]); + return new ts.NavigationBarItem(functionDeclaration.name.text, ts.ScriptElementKind.functionElement, getNodeModifiers(node), [getNodeSpan(node)]); } break; - case SyntaxKind.MemberVariableDeclaration: - var memberVariableDeclaration = node; - return new ts.NavigationBarItem(memberVariableDeclaration.variableDeclarator.propertyName.text(), ts.ScriptElementKind.memberVariableElement, getKindModifiers(memberVariableDeclaration.modifiers), [TextSpan.fromBounds(start(memberVariableDeclaration.variableDeclarator), end(memberVariableDeclaration.variableDeclarator))]); + case SyntaxKind.VariableDeclaration: + var variableDeclaration = node; + return new ts.NavigationBarItem(variableDeclaration.name.text, ts.ScriptElementKind.variableElement, ts.ScriptElementKindModifier.none, [getNodeSpan(node)]); - case SyntaxKind.VariableDeclarator: - var variableDeclarator = node; - return new ts.NavigationBarItem(variableDeclarator.propertyName.text(), ts.ScriptElementKind.variableElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(variableDeclarator), end(variableDeclarator))]); - - case SyntaxKind.ConstructorDeclaration: - var constructorDeclaration = node; - return new ts.NavigationBarItem("constructor", ts.ScriptElementKind.constructorImplementationElement, ts.ScriptElementKindModifier.none, [TextSpan.fromBounds(start(node), end(node))]); + case SyntaxKind.Constructor: + return new ts.NavigationBarItem("constructor", ts.ScriptElementKind.constructorImplementationElement, ts.ScriptElementKindModifier.none, [getNodeSpan(node)]); } return undefined; } - function createTopLevelItem(node: ISyntaxNode): ts.NavigationBarItem { - switch (node.kind()) { - case SyntaxKind.SourceUnit: - return createSourceUnitItem(node); + function createTopLevelItem(node: Node): ts.NavigationBarItem { + switch (node.kind) { + case SyntaxKind.SourceFile: + return createSourceFileItem(node); case SyntaxKind.ClassDeclaration: - return createClassItem(node); + return createClassItem(node); case SyntaxKind.EnumDeclaration: - return createEnumItem(node); + return createEnumItem(node); case SyntaxKind.InterfaceDeclaration: - return createIterfaceItem(node); + return createIterfaceItem(node); case SyntaxKind.ModuleDeclaration: - return createModuleItem(node); + return createModuleItem(node); case SyntaxKind.FunctionDeclaration: - return createFunctionItem(node); + return createFunctionItem(node); } return undefined; - function getModuleNames(node: TypeScript.ModuleDeclarationSyntax): string[] { + function getModuleNames(moduleDeclaration: ModuleDeclaration): string[]{ + // We want to maintain quotation marks. + if (moduleDeclaration.name.kind === SyntaxKind.StringLiteral) { + return [getSourceTextOfNode(moduleDeclaration.name)]; + } + + // Otherwise, we need to aggregate each identifier of the qualified name. var result: string[] = []; - if (node.stringLiteral) { - result.push(node.stringLiteral.text()); - } - else { - getModuleNamesHelper(node.name, result); - } + result.push(moduleDeclaration.name.text); + + while (moduleDeclaration.body && moduleDeclaration.body.kind === SyntaxKind.ModuleDeclaration) { + moduleDeclaration = moduleDeclaration.body; + + result.push(moduleDeclaration.name.text); + } return result; } - function getModuleNamesHelper(name: TypeScript.INameSyntax, result: string[]): void { - if (name.kind() === TypeScript.SyntaxKind.QualifiedName) { - var qualifiedName = name; - getModuleNamesHelper(qualifiedName.left, result); - result.push(qualifiedName.right.text()); - } - else { - result.push((name).text()); - } - } - - function createModuleItem(node: ModuleDeclarationSyntax): ts.NavigationBarItem { + function createModuleItem(node: ModuleDeclaration): NavigationBarItem { var moduleNames = getModuleNames(node); - - var childItems = getItemsWorker(getChildNodes(node.moduleElements), n => createChildItem(n)); + + var childItems = getItemsWorker(getChildNodes((getInnermostModule(node).body).statements), createChildItem); return new ts.NavigationBarItem(moduleNames.join("."), ts.ScriptElementKind.moduleElement, - getKindModifiers(node.modifiers), - [TextSpan.fromBounds(start(node), end(node))], + getNodeModifiers(node), + [getNodeSpan(node)], childItems, getIndent(node)); } - function createFunctionItem(node: FunctionDeclarationSyntax) { - var childItems = getItemsWorker(node.block.statements, n => createChildItem(n)); + function createFunctionItem(node: FunctionDeclaration) { + if (node.name && node.body && node.body.kind === SyntaxKind.FunctionBlock) { + var childItems = getItemsWorker((node.body).statements, createChildItem); - return new ts.NavigationBarItem(node.identifier.text(), - ts.ScriptElementKind.functionElement, - getKindModifiers(node.modifiers), - [TextSpan.fromBounds(start(node), end(node))], - childItems, - getIndent(node)); + return new ts.NavigationBarItem(node.name.text, + ts.ScriptElementKind.functionElement, + getNodeModifiers(node), + [getNodeSpan(node)], + childItems, + getIndent(node)); + } + + return undefined; } - function createSourceUnitItem(node: SourceUnitSyntax): ts.NavigationBarItem { - var childItems = getItemsWorker(getChildNodes(node.moduleElements), n => createChildItem(n)); + function createSourceFileItem(node: SourceFile): ts.NavigationBarItem { + var childItems = getItemsWorker(getChildNodes(node.statements), createChildItem); if (childItems === undefined || childItems.length === 0) { return undefined; @@ -299,50 +285,83 @@ module TypeScript.Services { return new ts.NavigationBarItem("", ts.ScriptElementKind.moduleElement, ts.ScriptElementKindModifier.none, - [TextSpan.fromBounds(start(node), end(node))], + [getNodeSpan(node)], childItems); } - function createClassItem(node: ClassDeclarationSyntax): ts.NavigationBarItem { - var constructor = ArrayUtilities.firstOrDefault( - node.classElements, n => n.kind() === SyntaxKind.ConstructorDeclaration); + function createClassItem(node: ClassDeclaration): ts.NavigationBarItem { + var childItems: NavigationBarItem[]; - // Add the constructor parameters in as children of the class (for property parameters). - var nodes: ISyntaxNode[] = constructor - ? (constructor.callSignature.parameterList.parameters).concat(node.classElements) - : node.classElements; + 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); + } - var childItems = getItemsWorker(nodes, n => createChildItem(n)); return new ts.NavigationBarItem( - node.identifier.text(), + node.name.text, ts.ScriptElementKind.classElement, - getKindModifiers(node.modifiers), - [TextSpan.fromBounds(start(node), end(node))], + getNodeModifiers(node), + [getNodeSpan(node)], childItems, getIndent(node)); } - function createEnumItem(node: TypeScript.EnumDeclarationSyntax): ts.NavigationBarItem { - var childItems = getItemsWorker(node.enumElements, n => createChildItem(n)); + function createEnumItem(node: EnumDeclaration): ts.NavigationBarItem { + var childItems = getItemsWorker(node.members, createChildItem); return new ts.NavigationBarItem( - node.identifier.text(), + node.name.text, ts.ScriptElementKind.enumElement, - getKindModifiers(node.modifiers), - [TextSpan.fromBounds(start(node), end(node))], + getNodeModifiers(node), + [getNodeSpan(node)], childItems, getIndent(node)); } - function createIterfaceItem(node: TypeScript.InterfaceDeclarationSyntax): ts.NavigationBarItem { - var childItems = getItemsWorker(node.body.typeMembers, n => createChildItem(n)); + function createIterfaceItem(node: InterfaceDeclaration): ts.NavigationBarItem { + var childItems = getItemsWorker(node.members, createChildItem); return new ts.NavigationBarItem( - node.identifier.text(), + node.name.text, ts.ScriptElementKind.interfaceElement, - getKindModifiers(node.modifiers), - [TextSpan.fromBounds(start(node), end(node))], + getNodeModifiers(node), + [getNodeSpan(node)], childItems, getIndent(node)); } } + + // TODO: use implementation in services.ts + function getNodeModifiers(node: Node): string { + var flags = node.flags; + var result: string[] = []; + + if (flags & NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); + 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 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()); + } } } \ No newline at end of file diff --git a/src/services/services.ts b/src/services/services.ts index ed32721a1ac..daaeb6d21bc 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -3121,9 +3121,7 @@ module ts { function getNavigationBarItems(filename: string): NavigationBarItem[] { filename = TypeScript.switchToForwardSlashes(filename); - - var syntaxTree = getSyntaxTree(filename); - return TypeScript.Services.getNavigationBarItemsHelper(syntaxTree.sourceUnit()); + return getNavigationBarItemsHelper(getCurrentSourceFile(filename)); } function getOutliningSpans(filename: string): OutliningSpan[] { From 915a27fc1aa24f252ab72d0f45b2f1a496a84ea5 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 18 Sep 2014 12:36:06 -0700 Subject: [PATCH 09/21] Added helper function for creating child items. --- .../getScriptLexicalStructureWalker.ts | 28 +++++++++++-------- 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/src/services/getScriptLexicalStructureWalker.ts b/src/services/getScriptLexicalStructureWalker.ts index d65e1d4a48d..653d2ffaf29 100644 --- a/src/services/getScriptLexicalStructureWalker.ts +++ b/src/services/getScriptLexicalStructureWalker.ts @@ -154,55 +154,59 @@ module ts { if ((node.flags & NodeFlags.Modifier) === 0) { return undefined; } - return new ts.NavigationBarItem(parameter.name.text, ts.ScriptElementKind.memberVariableElement, getNodeModifiers(node), [getNodeSpan(node)]); + return basicChildItem(node, parameter.name.text, ts.ScriptElementKind.memberVariableElement); case SyntaxKind.Method: var memberFunction = node; - return new ts.NavigationBarItem(memberFunction.name.text, ts.ScriptElementKind.memberFunctionElement, getNodeModifiers(node), [getNodeSpan(node)]); + return basicChildItem(node, memberFunction.name.text, ts.ScriptElementKind.memberFunctionElement); case SyntaxKind.GetAccessor: var getAccessor = node; - return new ts.NavigationBarItem(getAccessor.name.text, ts.ScriptElementKind.memberGetAccessorElement, getNodeModifiers(node), [getNodeSpan(node)]); + return basicChildItem(node, getAccessor.name.text, ts.ScriptElementKind.memberGetAccessorElement); case SyntaxKind.SetAccessor: var setAccessor = node; - return new ts.NavigationBarItem(setAccessor.name.text, ts.ScriptElementKind.memberSetAccessorElement, getNodeModifiers(node), [getNodeSpan(node)]); + return basicChildItem(node, setAccessor.name.text, ts.ScriptElementKind.memberSetAccessorElement); case SyntaxKind.IndexSignature: - return new ts.NavigationBarItem("[]", ts.ScriptElementKind.indexSignatureElement, ts.ScriptElementKindModifier.none, [getNodeSpan(node)]); + return basicChildItem(node, "[]", ts.ScriptElementKind.indexSignatureElement); case SyntaxKind.EnumMember: var enumElement = node; - return new ts.NavigationBarItem(enumElement.name.text, ts.ScriptElementKind.memberVariableElement, ts.ScriptElementKindModifier.none, [getNodeSpan(node)]); + return basicChildItem(node, enumElement.name.text, ts.ScriptElementKind.memberVariableElement); case SyntaxKind.CallSignature: - return new ts.NavigationBarItem("()", ts.ScriptElementKind.callSignatureElement, ts.ScriptElementKindModifier.none, []); + return basicChildItem(node, "()", ts.ScriptElementKind.callSignatureElement); case SyntaxKind.ConstructSignature: - return new ts.NavigationBarItem("new()", ts.ScriptElementKind.constructSignatureElement, ts.ScriptElementKindModifier.none, [getNodeSpan(node)]); + return basicChildItem(node, "new()", ts.ScriptElementKind.constructSignatureElement); case SyntaxKind.Property: var propertySignature = node; - return new ts.NavigationBarItem(propertySignature.name.text, ts.ScriptElementKind.memberVariableElement, getNodeModifiers(node), [getNodeSpan(node)]); + return basicChildItem(node, propertySignature.name.text, ts.ScriptElementKind.memberVariableElement); case SyntaxKind.FunctionDeclaration: var functionDeclaration = node; if (!isTopLevelFunctionDeclaration(functionDeclaration)) { - return new ts.NavigationBarItem(functionDeclaration.name.text, ts.ScriptElementKind.functionElement, getNodeModifiers(node), [getNodeSpan(node)]); + return basicChildItem(node, functionDeclaration.name.text, ts.ScriptElementKind.functionElement); } break; case SyntaxKind.VariableDeclaration: var variableDeclaration = node; - return new ts.NavigationBarItem(variableDeclaration.name.text, ts.ScriptElementKind.variableElement, ts.ScriptElementKindModifier.none, [getNodeSpan(node)]); + return basicChildItem(node, variableDeclaration.name.text, ts.ScriptElementKind.variableElement); case SyntaxKind.Constructor: - return new ts.NavigationBarItem("constructor", ts.ScriptElementKind.constructorImplementationElement, ts.ScriptElementKindModifier.none, [getNodeSpan(node)]); + return basicChildItem(node, "constructor", ts.ScriptElementKind.constructorImplementationElement); } return undefined; } + function basicChildItem(node: Node, name: string, scriptElementKind: string): NavigationBarItem { + return new NavigationBarItem(name, scriptElementKind, getNodeModifiers(node), [getNodeSpan(node)]); + } + function createTopLevelItem(node: Node): ts.NavigationBarItem { switch (node.kind) { case SyntaxKind.SourceFile: From 84c1d03dd2336fcaf48051838e5d209fb2ce3adc Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 18 Sep 2014 16:52:22 -0700 Subject: [PATCH 10/21] Removed duplicate 'getNodeModifiers'. --- .../getScriptLexicalStructureWalker.ts | 16 +----------- src/services/services.ts | 26 +++++++++---------- 2 files changed, 14 insertions(+), 28 deletions(-) diff --git a/src/services/getScriptLexicalStructureWalker.ts b/src/services/getScriptLexicalStructureWalker.ts index 653d2ffaf29..565c580c3b4 100644 --- a/src/services/getScriptLexicalStructureWalker.ts +++ b/src/services/getScriptLexicalStructureWalker.ts @@ -85,7 +85,7 @@ module ts { forEach((functionDeclaration.body).statements, s => s.kind === SyntaxKind.FunctionDeclaration); } - function getItemsWorker(nodes: Node[], createItem: (n: Node) => ts.NavigationBarItem): ts.NavigationBarItem[]{ + function getItemsWorker(nodes: Node[], createItem: (n: Node) => ts.NavigationBarItem): ts.NavigationBarItem[] { var items: ts.NavigationBarItem[] = []; if (!nodes) { @@ -341,20 +341,6 @@ module ts { } } - // TODO: use implementation in services.ts - function getNodeModifiers(node: Node): string { - var flags = node.flags; - var result: string[] = []; - - if (flags & NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); - 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 getInnermostModule(node: ModuleDeclaration): ModuleDeclaration { while (node.body.kind === SyntaxKind.ModuleDeclaration) { diff --git a/src/services/services.ts b/src/services/services.ts index 5bb632ba975..8d22c964e09 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1351,6 +1351,19 @@ 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.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) { @@ -2198,19 +2211,6 @@ module ts { } } - function getNodeModifiers(node: Node): string { - var flags = node.flags; - var result: string[] = []; - - if (flags & NodeFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier); - 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; - } - /// QuickInfo function getTypeAtPosition(fileName: string, position: number): TypeInfo { synchronizeHostData(); From 7bcab8b616672d16e3e662f73e8bd719e7c6989c Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 19 Sep 2014 12:28:49 -0700 Subject: [PATCH 11/21] Minor edit to test. --- tests/cases/fourslash/scriptLexicalStructureFunctions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cases/fourslash/scriptLexicalStructureFunctions.ts b/tests/cases/fourslash/scriptLexicalStructureFunctions.ts index 7723bd0ee68..a42a226c2c0 100644 --- a/tests/cases/fourslash/scriptLexicalStructureFunctions.ts +++ b/tests/cases/fourslash/scriptLexicalStructureFunctions.ts @@ -12,7 +12,7 @@ //// } ////} //// -////{| "itemName": "baz", "kind": "function" |}function baz() { +////{| "itemName": "baz", "kind": "function", "parentName": "" |}function baz() { //// var v = 10; ////} From 01d93b22ba88bc06ff9026f0d94f0047c8576d23 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 19 Sep 2014 13:54:34 -0700 Subject: [PATCH 12/21] External module items now display their base file name in quotes. --- src/compiler/core.ts | 14 ++++++++++++++ src/compiler/parser.ts | 9 +-------- src/services/getScriptLexicalStructureWalker.ts | 8 ++++++-- ...scriptLexicalStructureItemsExternalModules2.ts | 15 +++++++++++++++ 4 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 tests/cases/fourslash/scriptLexicalStructureItemsExternalModules2.ts diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 6bfa537c9f2..e6935afd599 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -521,6 +521,20 @@ 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; + } + export interface ObjectAllocator { getNodeConstructor(kind: SyntaxKind): new () => Node; getSymbolConstructor(): new (flags: SymbolFlags, name: string) => Symbol; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 4005a000dc8..8a977c8c764 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -17,20 +17,13 @@ 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; + return removeFileExtension(filename); } export function getSourceFileOfNode(node: Node): SourceFile { diff --git a/src/services/getScriptLexicalStructureWalker.ts b/src/services/getScriptLexicalStructureWalker.ts index 565c580c3b4..6c3de09af67 100644 --- a/src/services/getScriptLexicalStructureWalker.ts +++ b/src/services/getScriptLexicalStructureWalker.ts @@ -195,7 +195,7 @@ module ts { case SyntaxKind.VariableDeclaration: var variableDeclaration = node; return basicChildItem(node, variableDeclaration.name.text, ts.ScriptElementKind.variableElement); - + case SyntaxKind.Constructor: return basicChildItem(node, "constructor", ts.ScriptElementKind.constructorImplementationElement); } @@ -286,7 +286,11 @@ module ts { } hasGlobalNode = true; - return new ts.NavigationBarItem("", + var rootName = isExternalModule(node) ? + "\"" + getBaseFilename(removeFileExtension(normalizePath(node.filename))) + "\"" : + "" + + return new ts.NavigationBarItem(rootName, ts.ScriptElementKind.moduleElement, ts.ScriptElementKindModifier.none, [getNodeSpan(node)], 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 From be373647d0f78d4e78a5866323dac00b8b738a25 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Mon, 22 Sep 2014 11:43:52 -0700 Subject: [PATCH 13/21] Addressed CR feedback. --- src/compiler/core.ts | 2 +- .../getScriptLexicalStructureWalker.ts | 24 ++++++++----------- .../scriptLexicalStructureModules.ts | 12 +++++----- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/src/compiler/core.ts b/src/compiler/core.ts index e6935afd599..2ca50ae4923 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -522,8 +522,8 @@ module ts { } var supportedExtensions = [".d.ts", ".ts", ".js"]; - export function removeFileExtension(path: string): string { + export function removeFileExtension(path: string): string { for (var i = 0; i < supportedExtensions.length; i++) { var ext = supportedExtensions[i]; diff --git a/src/services/getScriptLexicalStructureWalker.ts b/src/services/getScriptLexicalStructureWalker.ts index 6c3de09af67..7dbfb0fbd14 100644 --- a/src/services/getScriptLexicalStructureWalker.ts +++ b/src/services/getScriptLexicalStructureWalker.ts @@ -88,10 +88,6 @@ module ts { function getItemsWorker(nodes: Node[], createItem: (n: Node) => ts.NavigationBarItem): ts.NavigationBarItem[] { var items: ts.NavigationBarItem[] = []; - if (!nodes) { - return items; - } - var keyToItem: Map = {}; for (var i = 0, n = nodes.length; i < n; i++) { @@ -162,39 +158,39 @@ module ts { case SyntaxKind.GetAccessor: var getAccessor = node; - return basicChildItem(node, getAccessor.name.text, ts.ScriptElementKind.memberGetAccessorElement); + return basicChildItem(node, getAccessor.name.text, ts.ScriptElementKind.memberGetAccessorElement); case SyntaxKind.SetAccessor: var setAccessor = node; - return basicChildItem(node, setAccessor.name.text, ts.ScriptElementKind.memberSetAccessorElement); + return basicChildItem(node, setAccessor.name.text, ts.ScriptElementKind.memberSetAccessorElement); case SyntaxKind.IndexSignature: - return basicChildItem(node, "[]", ts.ScriptElementKind.indexSignatureElement); + return basicChildItem(node, "[]", ts.ScriptElementKind.indexSignatureElement); case SyntaxKind.EnumMember: var enumElement = node; - return basicChildItem(node, enumElement.name.text, ts.ScriptElementKind.memberVariableElement); + return basicChildItem(node, enumElement.name.text, ts.ScriptElementKind.memberVariableElement); case SyntaxKind.CallSignature: - return basicChildItem(node, "()", ts.ScriptElementKind.callSignatureElement); + return basicChildItem(node, "()", ts.ScriptElementKind.callSignatureElement); case SyntaxKind.ConstructSignature: - return basicChildItem(node, "new()", ts.ScriptElementKind.constructSignatureElement); + return basicChildItem(node, "new()", ts.ScriptElementKind.constructSignatureElement); case SyntaxKind.Property: var propertySignature = node; - return basicChildItem(node, propertySignature.name.text, ts.ScriptElementKind.memberVariableElement); + return basicChildItem(node, propertySignature.name.text, ts.ScriptElementKind.memberVariableElement); case SyntaxKind.FunctionDeclaration: var functionDeclaration = node; if (!isTopLevelFunctionDeclaration(functionDeclaration)) { - return basicChildItem(node, functionDeclaration.name.text, ts.ScriptElementKind.functionElement); + return basicChildItem(node, functionDeclaration.name.text, ts.ScriptElementKind.functionElement); } break; case SyntaxKind.VariableDeclaration: var variableDeclaration = node; - return basicChildItem(node, variableDeclaration.name.text, ts.ScriptElementKind.variableElement); + return basicChildItem(node, variableDeclaration.name.text, ts.ScriptElementKind.variableElement); case SyntaxKind.Constructor: return basicChildItem(node, "constructor", ts.ScriptElementKind.constructorImplementationElement); @@ -307,7 +303,7 @@ module ts { // Add the constructor parameters in as children of the class (for property parameters). var nodes: Node[] = constructor - ? (constructor.parameters).concat(node.members) + ? constructor.parameters.concat(node.members) : node.members; var childItems = getItemsWorker(nodes, createChildItem); diff --git a/tests/cases/fourslash/scriptLexicalStructureModules.ts b/tests/cases/fourslash/scriptLexicalStructureModules.ts index 4331e64e0b0..ee0f91cc73c 100644 --- a/tests/cases/fourslash/scriptLexicalStructureModules.ts +++ b/tests/cases/fourslash/scriptLexicalStructureModules.ts @@ -9,29 +9,29 @@ //// ////{| "itemName": "A.B.C", "kind": "module" |} ////module A.B.C { -//// {| "itemName": "x", "kind": "var", "parent": "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", "parent": "A.B" |} +//// {| "itemName": "y", "kind": "var", "parentName": "A.B" |} //// export var y; ////} //// ////{| "itemName": "A", "kind": "module" |} ////module A { -//// {| "itemName": "z", "kind": "var", "parent": "A" |} +//// {| "itemName": "z", "kind": "var", "parentName": "A" |} //// export var z; ////} //// ////{| "itemName": "A", "kind": "module" |} ////module A { -//// {| "itemName": "B", "kind": "module", "parent": "E" |} +//// {| "itemName": "B", "kind": "module", "parentName": "E" |} //// module B { -//// {| "itemName": "C", "kind": "module", "parent": "F" |} +//// {| "itemName": "C", "kind": "module", "parentName": "F" |} //// module C { -//// {| "itemName": "x", "kind": "var", "parent": "C" |} +//// {| "itemName": "x", "kind": "var", "parentName": "C" |} //// declare var x; //// } //// } From 2c99556b3122bec68993d09b05156f00459f60d0 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 23 Sep 2014 08:18:37 -0700 Subject: [PATCH 14/21] Use push.apply to push multiple elements. --- src/services/getScriptLexicalStructureWalker.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/services/getScriptLexicalStructureWalker.ts b/src/services/getScriptLexicalStructureWalker.ts index 7dbfb0fbd14..7013460598f 100644 --- a/src/services/getScriptLexicalStructureWalker.ts +++ b/src/services/getScriptLexicalStructureWalker.ts @@ -31,9 +31,7 @@ module ts { childNodes.push(node); } else if (node.kind === SyntaxKind.VariableStatement) { - forEach((node).declarations, declaration => { - childNodes.push(declaration); - }); + childNodes.push.apply(childNodes, (node).declarations); } } From a98cca77234583adc13ae7e0b40ba4e5baea9d99 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Thu, 25 Sep 2014 13:10:04 -0700 Subject: [PATCH 15/21] Properly support string-literal property names and escape external module names. --- src/compiler/core.ts | 23 +++++++++ src/compiler/emitter.ts | 23 --------- .../getScriptLexicalStructureWalker.ts | 50 +++++++++++++------ ...ptLexicalStructureItemsExternalModules3.ts | 15 ++++++ .../scriptLexicalStructureModules.ts | 2 +- ...icalStructureMultilineStringIdentifiers.ts | 40 +++++++++++++++ 6 files changed, 113 insertions(+), 40 deletions(-) create mode 100644 tests/cases/fourslash/scriptLexicalStructureItemsExternalModules3.ts create mode 100644 tests/cases/fourslash/scriptLexicalStructureMultilineStringIdentifiers.ts diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 2ca50ae4923..d95bc4f89ce 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -535,6 +535,29 @@ module ts { 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 74b0533e5b4..793660763a9 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -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++) { diff --git a/src/services/getScriptLexicalStructureWalker.ts b/src/services/getScriptLexicalStructureWalker.ts index 7013460598f..c6158bfead7 100644 --- a/src/services/getScriptLexicalStructureWalker.ts +++ b/src/services/getScriptLexicalStructureWalker.ts @@ -151,23 +151,23 @@ module ts { return basicChildItem(node, parameter.name.text, ts.ScriptElementKind.memberVariableElement); case SyntaxKind.Method: - var memberFunction = node; - return basicChildItem(node, memberFunction.name.text, ts.ScriptElementKind.memberFunctionElement); + var method = node; + return basicChildItem(node, getPropertyText(method.name), ts.ScriptElementKind.memberFunctionElement); case SyntaxKind.GetAccessor: var getAccessor = node; - return basicChildItem(node, getAccessor.name.text, ts.ScriptElementKind.memberGetAccessorElement); + return basicChildItem(node, getPropertyText(getAccessor.name), ts.ScriptElementKind.memberGetAccessorElement); case SyntaxKind.SetAccessor: var setAccessor = node; - return basicChildItem(node, setAccessor.name.text, ts.ScriptElementKind.memberSetAccessorElement); + return basicChildItem(node, getPropertyText(setAccessor.name), ts.ScriptElementKind.memberSetAccessorElement); case SyntaxKind.IndexSignature: return basicChildItem(node, "[]", ts.ScriptElementKind.indexSignatureElement); case SyntaxKind.EnumMember: - var enumElement = node; - return basicChildItem(node, enumElement.name.text, ts.ScriptElementKind.memberVariableElement); + var enumMember = node; + return basicChildItem(node, getPropertyText(enumMember.name), ts.ScriptElementKind.memberVariableElement); case SyntaxKind.CallSignature: return basicChildItem(node, "()", ts.ScriptElementKind.callSignatureElement); @@ -176,8 +176,8 @@ module ts { return basicChildItem(node, "new()", ts.ScriptElementKind.constructSignatureElement); case SyntaxKind.Property: - var propertySignature = node; - return basicChildItem(node, propertySignature.name.text, ts.ScriptElementKind.memberVariableElement); + var property = node; + return basicChildItem(node, getPropertyText(property.name), ts.ScriptElementKind.memberVariableElement); case SyntaxKind.FunctionDeclaration: var functionDeclaration = node; @@ -224,13 +224,13 @@ module ts { return undefined; - function getModuleNames(moduleDeclaration: ModuleDeclaration): string[]{ + function getModuleName(moduleDeclaration: ModuleDeclaration): string { // We want to maintain quotation marks. if (moduleDeclaration.name.kind === SyntaxKind.StringLiteral) { - return [getSourceTextOfNode(moduleDeclaration.name)]; + return getPropertyText(moduleDeclaration.name); } - // Otherwise, we need to aggregate each identifier of the qualified name. + // Otherwise, we need to aggregate each identifier to build up the qualified name. var result: string[] = []; result.push(moduleDeclaration.name.text); @@ -241,15 +241,15 @@ module ts { result.push(moduleDeclaration.name.text); } - return result; + return result.join("."); } function createModuleItem(node: ModuleDeclaration): NavigationBarItem { - var moduleNames = getModuleNames(node); + var moduleName = getModuleName(node); var childItems = getItemsWorker(getChildNodes((getInnermostModule(node).body).statements), createChildItem); - return new ts.NavigationBarItem(moduleNames.join("."), + return new ts.NavigationBarItem(moduleName, ts.ScriptElementKind.moduleElement, getNodeModifiers(node), [getNodeSpan(node)], @@ -281,7 +281,7 @@ module ts { hasGlobalNode = true; var rootName = isExternalModule(node) ? - "\"" + getBaseFilename(removeFileExtension(normalizePath(node.filename))) + "\"" : + "\"" + escapeString(getBaseFilename(removeFileExtension(normalizePath(node.filename)))) + "\"" : "" return new ts.NavigationBarItem(rootName, @@ -340,7 +340,6 @@ module ts { } function getInnermostModule(node: ModuleDeclaration): ModuleDeclaration { - while (node.body.kind === SyntaxKind.ModuleDeclaration) { node = node.body; } @@ -351,5 +350,24 @@ module ts { function getNodeSpan(node: Node) { return TypeScript.TextSpan.fromBounds(node.getStart(), node.getEnd()); } + + function getPropertyText(node: Node): string { + if (node.kind === SyntaxKind.Identifier) { + return (node).text; + } + + if (node.kind === SyntaxKind.StringLiteral) { + // normalize the quotes and remove all '\{newline}'s from the original text. + var text = getSourceTextOfNodeFromSourceText(sourceFile.text, node); + text = text.substring(1, text.length - 1).replace(/\\\r?\n/g, ""); + return "\"" + text + "\""; + } + + if (node.kind === SyntaxKind.NumericLiteral) { + return (node).text; + } + + Debug.fail("getPropertyText given a property that is neither an identifier nor a literal expression."); + } } } \ No newline at end of file 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/scriptLexicalStructureModules.ts b/tests/cases/fourslash/scriptLexicalStructureModules.ts index ee0f91cc73c..602cc170dee 100644 --- a/tests/cases/fourslash/scriptLexicalStructureModules.ts +++ b/tests/cases/fourslash/scriptLexicalStructureModules.ts @@ -3,7 +3,7 @@ ////declare module "X.Y.Z" { ////} //// -////{| "itemName": "'X2.Y2.Z2'", "kind": "module" |} +////{| "itemName": "\"X2.Y2.Z2\"", "kind": "module" |} ////declare module 'X2.Y2.Z2' { ////} //// diff --git a/tests/cases/fourslash/scriptLexicalStructureMultilineStringIdentifiers.ts b/tests/cases/fourslash/scriptLexicalStructureMultilineStringIdentifiers.ts new file mode 100644 index 00000000000..e0a44ba2685 --- /dev/null +++ b/tests/cases/fourslash/scriptLexicalStructureMultilineStringIdentifiers.ts @@ -0,0 +1,40 @@ + +////{| "itemName": "\"Multiline\\r\\nMadness\"", "kind": "module" |} +////declare module "Multiline\r\nMadness" { +////} +//// +////{| "itemName": "\"MultilineMadness\"", "kind": "module" |} +////declare module "Multiline\ +////Madness" { +////} +////declare module "MultilineMadness" {} +//// +////{| "itemName": "Foo", "kind": "interface" |} +////interface Foo { +//// {| "itemName": "\"a1\\\\\\r\\nb\"", "kind": "property", "parentName": "Foo" |} +//// "a1\\\r\nb"; +//// {| "itemName": "\"a2 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 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(8); // interface w/ 2 properties, class w/ 2 properties, 1 merged module, and 1 independent module From a87685b0d2a73d97bcc516e1a1cb112d0b3268fc Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Mon, 29 Sep 2014 17:58:58 -0700 Subject: [PATCH 16/21] Simply use source text from now on. --- .../getScriptLexicalStructureWalker.ts | 37 ++++++------------- 1 file changed, 11 insertions(+), 26 deletions(-) diff --git a/src/services/getScriptLexicalStructureWalker.ts b/src/services/getScriptLexicalStructureWalker.ts index c6158bfead7..bafc7c5dd16 100644 --- a/src/services/getScriptLexicalStructureWalker.ts +++ b/src/services/getScriptLexicalStructureWalker.ts @@ -148,26 +148,26 @@ module ts { if ((node.flags & NodeFlags.Modifier) === 0) { return undefined; } - return basicChildItem(node, parameter.name.text, ts.ScriptElementKind.memberVariableElement); + return basicChildItem(node, getSourceText(parameter.name), ts.ScriptElementKind.memberVariableElement); case SyntaxKind.Method: var method = node; - return basicChildItem(node, getPropertyText(method.name), ts.ScriptElementKind.memberFunctionElement); + return basicChildItem(node, getSourceText(method.name), ts.ScriptElementKind.memberFunctionElement); case SyntaxKind.GetAccessor: var getAccessor = node; - return basicChildItem(node, getPropertyText(getAccessor.name), ts.ScriptElementKind.memberGetAccessorElement); + return basicChildItem(node, getSourceText(getAccessor.name), ts.ScriptElementKind.memberGetAccessorElement); case SyntaxKind.SetAccessor: var setAccessor = node; - return basicChildItem(node, getPropertyText(setAccessor.name), ts.ScriptElementKind.memberSetAccessorElement); + return basicChildItem(node, getSourceText(setAccessor.name), ts.ScriptElementKind.memberSetAccessorElement); case SyntaxKind.IndexSignature: return basicChildItem(node, "[]", ts.ScriptElementKind.indexSignatureElement); case SyntaxKind.EnumMember: var enumMember = node; - return basicChildItem(node, getPropertyText(enumMember.name), ts.ScriptElementKind.memberVariableElement); + return basicChildItem(node, getSourceText(enumMember.name), ts.ScriptElementKind.memberVariableElement); case SyntaxKind.CallSignature: return basicChildItem(node, "()", ts.ScriptElementKind.callSignatureElement); @@ -177,18 +177,18 @@ module ts { case SyntaxKind.Property: var property = node; - return basicChildItem(node, getPropertyText(property.name), ts.ScriptElementKind.memberVariableElement); + return basicChildItem(node, getSourceText(property.name), ts.ScriptElementKind.memberVariableElement); case SyntaxKind.FunctionDeclaration: var functionDeclaration = node; if (!isTopLevelFunctionDeclaration(functionDeclaration)) { - return basicChildItem(node, functionDeclaration.name.text, ts.ScriptElementKind.functionElement); + return basicChildItem(node, getSourceText(functionDeclaration.name), ts.ScriptElementKind.functionElement); } break; case SyntaxKind.VariableDeclaration: var variableDeclaration = node; - return basicChildItem(node, variableDeclaration.name.text, ts.ScriptElementKind.variableElement); + return basicChildItem(node, getSourceText(variableDeclaration.name), ts.ScriptElementKind.variableElement); case SyntaxKind.Constructor: return basicChildItem(node, "constructor", ts.ScriptElementKind.constructorImplementationElement); @@ -227,7 +227,7 @@ module ts { function getModuleName(moduleDeclaration: ModuleDeclaration): string { // We want to maintain quotation marks. if (moduleDeclaration.name.kind === SyntaxKind.StringLiteral) { - return getPropertyText(moduleDeclaration.name); + return getSourceText(moduleDeclaration.name); } // Otherwise, we need to aggregate each identifier to build up the qualified name. @@ -351,23 +351,8 @@ module ts { return TypeScript.TextSpan.fromBounds(node.getStart(), node.getEnd()); } - function getPropertyText(node: Node): string { - if (node.kind === SyntaxKind.Identifier) { - return (node).text; - } - - if (node.kind === SyntaxKind.StringLiteral) { - // normalize the quotes and remove all '\{newline}'s from the original text. - var text = getSourceTextOfNodeFromSourceText(sourceFile.text, node); - text = text.substring(1, text.length - 1).replace(/\\\r?\n/g, ""); - return "\"" + text + "\""; - } - - if (node.kind === SyntaxKind.NumericLiteral) { - return (node).text; - } - - Debug.fail("getPropertyText given a property that is neither an identifier nor a literal expression."); + function getSourceText(node: Node): string { + return getSourceTextOfNodeFromSourceText(sourceFile.text, node); } } } \ No newline at end of file From 379f6ce75857524a652b2e3e2fb5d73d29909526 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Tue, 30 Sep 2014 11:58:56 -0700 Subject: [PATCH 17/21] Minor cleanup, added getScriptLexicalStructureWalker.ts Jakefile. --- Jakefile | 1 + .../scriptLexicalStructureItemsContainsNoAnonymousFunctions.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Jakefile b/Jakefile index 0bdb573914f..553372f43ec 100644 --- a/Jakefile +++ b/Jakefile @@ -54,6 +54,7 @@ var servicesSources = [ }).concat([ "services.ts", "shims.ts", + "getScriptLexicalStructureWalker.ts" ].map(function (f) { return path.join(servicesDirectory, f); })); diff --git a/tests/cases/fourslash/scriptLexicalStructureItemsContainsNoAnonymousFunctions.ts b/tests/cases/fourslash/scriptLexicalStructureItemsContainsNoAnonymousFunctions.ts index 2c8ef5825db..531575d6d10 100644 --- a/tests/cases/fourslash/scriptLexicalStructureItemsContainsNoAnonymousFunctions.ts +++ b/tests/cases/fourslash/scriptLexicalStructureItemsContainsNoAnonymousFunctions.ts @@ -28,7 +28,7 @@ ////} ////function bar() { ////} -debugger; + goTo.marker("file1"); verify.getScriptLexicalStructureListCount(0); From 4ba0ce433f84daf42aa70764e2a4754610eb614a Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 3 Oct 2014 16:12:59 -0700 Subject: [PATCH 18/21] Renamed 'getScriptLexicalItemsWalkerSuperCala[...].ts' to 'navigationBar.ts'. --- Jakefile | 2 +- .../{getScriptLexicalStructureWalker.ts => navigationBar.ts} | 4 ++-- src/services/services.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) rename src/services/{getScriptLexicalStructureWalker.ts => navigationBar.ts} (96%) diff --git a/Jakefile b/Jakefile index 4929a9e1468..4f2808dcbd1 100644 --- a/Jakefile +++ b/Jakefile @@ -58,7 +58,7 @@ var servicesSources = [ "shims.ts", "signatureHelp.ts", "utilities.ts", - "getScriptLexicalStructureWalker.ts" + "navigationBar.ts" ].map(function (f) { return path.join(servicesDirectory, f); })); diff --git a/src/services/getScriptLexicalStructureWalker.ts b/src/services/navigationBar.ts similarity index 96% rename from src/services/getScriptLexicalStructureWalker.ts rename to src/services/navigationBar.ts index 2162c619fa9..4b5904e3cff 100644 --- a/src/services/getScriptLexicalStructureWalker.ts +++ b/src/services/navigationBar.ts @@ -1,8 +1,8 @@ /// /// -module ts { - export function getNavigationBarItemsHelper(sourceFile: SourceFile): ts.NavigationBarItem[] { +module ts.NavigationBar { + export function getNavigationBarItems(sourceFile: SourceFile): ts.NavigationBarItem[] { var hasGlobalNode = false; return getItemsWorker(getTopLevelNodes(sourceFile), createTopLevelItem); diff --git a/src/services/services.ts b/src/services/services.ts index 5605d0f6c84..320e0072d97 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -6,7 +6,7 @@ /// /// -/// +/// /// /// /// @@ -3907,7 +3907,7 @@ module ts { function getNavigationBarItems(filename: string): NavigationBarItem[] { filename = TypeScript.switchToForwardSlashes(filename); - return getNavigationBarItemsHelper(getCurrentSourceFile(filename)); + return NavigationBar.getNavigationBarItems(getCurrentSourceFile(filename)); } function getSemanticClassifications(fileName: string, span: TypeScript.TextSpan): ClassifiedSpan[] { From 7d9bf5093bcebc68620aa906d2f41c0df24dcc7d Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 3 Oct 2014 16:19:30 -0700 Subject: [PATCH 19/21] Replaced 'getModuleNameFromFilename' with 'removeFileExtension'. --- src/compiler/binder.ts | 2 +- src/compiler/emitter.ts | 8 ++++---- src/compiler/parser.ts | 4 ---- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts index 3959335542c..16302ecf4b5 100644 --- a/src/compiler/binder.ts +++ b/src/compiler/binder.ts @@ -332,7 +332,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/emitter.ts b/src/compiler/emitter.ts index 1b7fff6747f..5dfedc37e0a 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; @@ -3141,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)), @@ -3214,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 ede29fba891..9a11fef88b0 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -22,10 +22,6 @@ module ts { amdDependencies: string[]; } - export function getModuleNameFromFilename(filename: string) { - return removeFileExtension(filename); - } - export function getSourceFileOfNode(node: Node): SourceFile { while (node && node.kind !== SyntaxKind.SourceFile) node = node.parent; return node; From 1814261269dcfb450cc54c87963e5629004bd0bc Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 3 Oct 2014 16:57:41 -0700 Subject: [PATCH 20/21] Moved 'basicChildItem' to 'createChildItem' and renamed it 'createItem'. --- src/services/navigationBar.ts | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index 4b5904e3cff..e9a8a75c8f0 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -3,11 +3,15 @@ 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; @@ -150,57 +154,57 @@ module ts.NavigationBar { return undefined; } - return basicChildItem(node, getSourceText(parameter.name), ts.ScriptElementKind.memberVariableElement); + return createItem(node, getSourceText(parameter.name), ts.ScriptElementKind.memberVariableElement); case SyntaxKind.Method: var method = node; - return basicChildItem(node, getSourceText(method.name), ts.ScriptElementKind.memberFunctionElement); + return createItem(node, getSourceText(method.name), ts.ScriptElementKind.memberFunctionElement); case SyntaxKind.GetAccessor: var getAccessor = node; - return basicChildItem(node, getSourceText(getAccessor.name), ts.ScriptElementKind.memberGetAccessorElement); + return createItem(node, getSourceText(getAccessor.name), ts.ScriptElementKind.memberGetAccessorElement); case SyntaxKind.SetAccessor: var setAccessor = node; - return basicChildItem(node, getSourceText(setAccessor.name), ts.ScriptElementKind.memberSetAccessorElement); + return createItem(node, getSourceText(setAccessor.name), ts.ScriptElementKind.memberSetAccessorElement); case SyntaxKind.IndexSignature: - return basicChildItem(node, "[]", ts.ScriptElementKind.indexSignatureElement); + return createItem(node, "[]", ts.ScriptElementKind.indexSignatureElement); case SyntaxKind.EnumMember: var enumMember = node; - return basicChildItem(node, getSourceText(enumMember.name), ts.ScriptElementKind.memberVariableElement); + return createItem(node, getSourceText(enumMember.name), ts.ScriptElementKind.memberVariableElement); case SyntaxKind.CallSignature: - return basicChildItem(node, "()", ts.ScriptElementKind.callSignatureElement); + return createItem(node, "()", ts.ScriptElementKind.callSignatureElement); case SyntaxKind.ConstructSignature: - return basicChildItem(node, "new()", ts.ScriptElementKind.constructSignatureElement); + return createItem(node, "new()", ts.ScriptElementKind.constructSignatureElement); case SyntaxKind.Property: var property = node; - return basicChildItem(node, getSourceText(property.name), ts.ScriptElementKind.memberVariableElement); + return createItem(node, getSourceText(property.name), ts.ScriptElementKind.memberVariableElement); case SyntaxKind.FunctionDeclaration: var functionDeclaration = node; if (!isTopLevelFunctionDeclaration(functionDeclaration)) { - return basicChildItem(node, getSourceText(functionDeclaration.name), ts.ScriptElementKind.functionElement); + return createItem(node, getSourceText(functionDeclaration.name), ts.ScriptElementKind.functionElement); } break; case SyntaxKind.VariableDeclaration: var variableDeclaration = node; - return basicChildItem(node, getSourceText(variableDeclaration.name), ts.ScriptElementKind.variableElement); + return createItem(node, getSourceText(variableDeclaration.name), ts.ScriptElementKind.variableElement); case SyntaxKind.Constructor: - return basicChildItem(node, "constructor", ts.ScriptElementKind.constructorImplementationElement); + return createItem(node, "constructor", ts.ScriptElementKind.constructorImplementationElement); } return undefined; - } - function basicChildItem(node: Node, name: string, scriptElementKind: string): NavigationBarItem { - return getNavigationBarItem(name, scriptElementKind, getNodeModifiers(node), [getNodeSpan(node)]); + 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 { From 208e36d294c18efe84cf663dda01d51579aa3824 Mon Sep 17 00:00:00 2001 From: Daniel Rosenwasser Date: Fri, 3 Oct 2014 17:28:48 -0700 Subject: [PATCH 21/21] Cover all top-level items in 'getIndent'. --- src/services/navigationBar.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index e9a8a75c8f0..825d46a1f65 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -16,8 +16,20 @@ module ts.NavigationBar { var current = node.parent; while (current) { - if (current.kind === SyntaxKind.ModuleDeclaration || current.kind === SyntaxKind.FunctionDeclaration) { - indent++; + 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; @@ -207,7 +219,7 @@ module ts.NavigationBar { } } - function getNavigationBarItem(text: string, kind: string, kindModifiers: string, spans: TypeScript.TextSpan[], childItems: ts.NavigationBarItem[]= [], indent: number = 0): ts.NavigationBarItem { + function getNavigationBarItem(text: string, kind: string, kindModifiers: string, spans: TypeScript.TextSpan[], childItems: ts.NavigationBarItem[] = [], indent: number = 0): ts.NavigationBarItem { return { text: text, kind: kind,