From 9f28e88ff1a1a92ef374feccafe9a62a55195795 Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Sun, 22 Feb 2015 18:59:27 -0800 Subject: [PATCH 1/8] insert space after '?' only in conditional operator --- src/services/formatting/rules.ts | 16 +++++++++++++--- tests/cases/fourslash/formattingQMark.ts | 12 ++++++++++++ tests/cases/fourslash/genericsFormatting.ts | 2 +- 3 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 tests/cases/fourslash/formattingQMark.ts diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index b5470579787f4..44970ac9f098a 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -37,7 +37,11 @@ module ts.formatting { public NoSpaceBeforeColon: Rule; public NoSpaceBeforeQMark: Rule; public SpaceAfterColon: Rule; - public SpaceAfterQMark: Rule; + // insert space after '?' only when it is used in conditional operator + public SpaceAfterQMarkInConditionalOperator: Rule; + // in other cases there should be no space between '?' and next token + public NoSpaceAfterQMark: Rule; + public SpaceAfterSemicolon: Rule; // Space/new line after }. @@ -217,7 +221,8 @@ module ts.formatting { this.NoSpaceBeforeColon = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.ColonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); this.NoSpaceBeforeQMark = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.QuestionToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); this.SpaceAfterColon = new Rule(RuleDescriptor.create3(SyntaxKind.ColonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Space)); - this.SpaceAfterQMark = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Space)); + this.SpaceAfterQMarkInConditionalOperator = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsConditionalOperatorContext), RuleAction.Space)); + this.NoSpaceAfterQMark = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); this.SpaceAfterSemicolon = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); // Space after }. @@ -341,7 +346,8 @@ module ts.formatting { this.HighPriorityCommonRules = [ this.IgnoreBeforeComment, this.IgnoreAfterLineComment, - this.NoSpaceBeforeColon, this.SpaceAfterColon, this.NoSpaceBeforeQMark, this.SpaceAfterQMark, + this.NoSpaceBeforeColon, this.SpaceAfterColon, this.NoSpaceBeforeQMark, this.SpaceAfterQMarkInConditionalOperator, + this.NoSpaceAfterQMark, this.NoSpaceBeforeDot, this.NoSpaceAfterDot, this.NoSpaceAfterUnaryPrefixOperator, this.NoSpaceAfterUnaryPreincrementOperator, this.NoSpaceAfterUnaryPredecrementOperator, @@ -475,6 +481,10 @@ module ts.formatting { return !Rules.IsBinaryOpContext(context); } + static IsConditionalOperatorContext(context: FormattingContext): boolean { + return context.contextNode.kind === SyntaxKind.ConditionalExpression; + } + static IsSameLineTokenOrBeforeMultilineBlockContext(context: FormattingContext): boolean { //// This check is mainly used inside SpaceBeforeOpenBraceInControl and SpaceBeforeOpenBraceInFunction. //// diff --git a/tests/cases/fourslash/formattingQMark.ts b/tests/cases/fourslash/formattingQMark.ts new file mode 100644 index 0000000000000..83ca56a49f660 --- /dev/null +++ b/tests/cases/fourslash/formattingQMark.ts @@ -0,0 +1,12 @@ +/// + +////interface A { +/////*1*/ foo? (); +/////*2*/ foo? (); +////} + +format.document(); +goTo.marker("1"); +verify.currentLineContentIs(" foo?();"); +goTo.marker("2"); +verify.currentLineContentIs(" foo?();"); \ No newline at end of file diff --git a/tests/cases/fourslash/genericsFormatting.ts b/tests/cases/fourslash/genericsFormatting.ts index f6f1426316c64..36833cadd10a1 100644 --- a/tests/cases/fourslash/genericsFormatting.ts +++ b/tests/cases/fourslash/genericsFormatting.ts @@ -30,4 +30,4 @@ goTo.marker("inNewSignature"); verify.currentLineContentIs(" new (a: T);"); goTo.marker("inOptionalMethodSignature"); -verify.currentLineContentIs(" op? (a: T, b: M);"); \ No newline at end of file +verify.currentLineContentIs(" op?(a: T, b: M);"); \ No newline at end of file From a25c99e146d42ac774d6bdb83a20d8a2be67caea Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Sun, 22 Feb 2015 19:02:48 -0800 Subject: [PATCH 2/8] added missing test --- tests/cases/fourslash/formattingConditionalOperator.ts | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/cases/fourslash/formattingConditionalOperator.ts diff --git a/tests/cases/fourslash/formattingConditionalOperator.ts b/tests/cases/fourslash/formattingConditionalOperator.ts new file mode 100644 index 0000000000000..545adb572b152 --- /dev/null +++ b/tests/cases/fourslash/formattingConditionalOperator.ts @@ -0,0 +1,6 @@ +/// + +////var x=true?1:2 +format.document(); +goTo.bof(); +verify.currentLineContentIs("var x = true ? 1 : 2");; \ No newline at end of file From e549f2f0af872d8ff0b85a298fb865ba6a87884e Mon Sep 17 00:00:00 2001 From: Vladimir Matveev Date: Sun, 22 Feb 2015 22:34:59 -0800 Subject: [PATCH 3/8] renamed QMark to QuestionMark --- src/services/formatting/rules.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index 44970ac9f098a..320df83e35acf 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -35,12 +35,12 @@ module ts.formatting { // Space after keyword but not before ; or : or ? public NoSpaceBeforeSemicolon: Rule; public NoSpaceBeforeColon: Rule; - public NoSpaceBeforeQMark: Rule; + public NoSpaceBeforeQuestionMark: Rule; public SpaceAfterColon: Rule; // insert space after '?' only when it is used in conditional operator - public SpaceAfterQMarkInConditionalOperator: Rule; + public SpaceAfterQuestionMarkInConditionalOperator: Rule; // in other cases there should be no space between '?' and next token - public NoSpaceAfterQMark: Rule; + public NoSpaceAfterQuestionMark: Rule; public SpaceAfterSemicolon: Rule; @@ -219,10 +219,10 @@ module ts.formatting { // Space after keyword but not before ; or : or ? this.NoSpaceBeforeSemicolon = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.SemicolonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); this.NoSpaceBeforeColon = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.ColonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); - this.NoSpaceBeforeQMark = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.QuestionToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); + this.NoSpaceBeforeQuestionMark = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.QuestionToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete)); this.SpaceAfterColon = new Rule(RuleDescriptor.create3(SyntaxKind.ColonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Space)); - this.SpaceAfterQMarkInConditionalOperator = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsConditionalOperatorContext), RuleAction.Space)); - this.NoSpaceAfterQMark = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); + this.SpaceAfterQuestionMarkInConditionalOperator = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsConditionalOperatorContext), RuleAction.Space)); + this.NoSpaceAfterQuestionMark = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete)); this.SpaceAfterSemicolon = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space)); // Space after }. @@ -346,8 +346,8 @@ module ts.formatting { this.HighPriorityCommonRules = [ this.IgnoreBeforeComment, this.IgnoreAfterLineComment, - this.NoSpaceBeforeColon, this.SpaceAfterColon, this.NoSpaceBeforeQMark, this.SpaceAfterQMarkInConditionalOperator, - this.NoSpaceAfterQMark, + this.NoSpaceBeforeColon, this.SpaceAfterColon, this.NoSpaceBeforeQuestionMark, this.SpaceAfterQuestionMarkInConditionalOperator, + this.NoSpaceAfterQuestionMark, this.NoSpaceBeforeDot, this.NoSpaceAfterDot, this.NoSpaceAfterUnaryPrefixOperator, this.NoSpaceAfterUnaryPreincrementOperator, this.NoSpaceAfterUnaryPredecrementOperator, From 61e6b3258da980efdb340ed0b76c3d20a76b3ebc Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 24 Feb 2015 01:18:31 -0800 Subject: [PATCH 4/8] Remove debugger statement --- tests/cases/fourslash/goToDefinitionImportedNames7.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/cases/fourslash/goToDefinitionImportedNames7.ts b/tests/cases/fourslash/goToDefinitionImportedNames7.ts index 5a43f0a1ee9ae..46d09012d4099 100644 --- a/tests/cases/fourslash/goToDefinitionImportedNames7.ts +++ b/tests/cases/fourslash/goToDefinitionImportedNames7.ts @@ -10,8 +10,6 @@ ////} ////export = Class; -debugger; - goTo.file("b.ts"); goTo.marker('classAliasDefinition'); From e93748ac58eaea3995260af25b0562eaad68af0e Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 24 Feb 2015 01:19:48 -0800 Subject: [PATCH 5/8] Support find references on the new import/export syntax --- src/services/services.ts | 68 +++++++++++++++++-- .../fourslash/findAllRefsOnImportAliases.ts | 29 ++++++++ .../fourslash/findAllRefsOnImportAliases2.ts | 31 +++++++++ 3 files changed, 122 insertions(+), 6 deletions(-) create mode 100644 tests/cases/fourslash/findAllRefsOnImportAliases.ts create mode 100644 tests/cases/fourslash/findAllRefsOnImportAliases2.ts diff --git a/src/services/services.ts b/src/services/services.ts index db6a09c1a7115..708869fddf548 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -3986,7 +3986,7 @@ module ts { var searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), declarations); // Get the text to search for, we need to normalize it as external module names will have quote - var declaredName = getDeclaredName(symbol); + var declaredName = getDeclaredName(symbol, node); // Try to get the smallest valid scope that we can limit our search to; // otherwise we'll need to search globally (i.e. include each file). @@ -4003,7 +4003,7 @@ module ts { getReferencesInNode(sourceFiles[0], symbol, declaredName, node, searchMeaning, findInStrings, findInComments, result); } else { - var internedName = getInternedName(symbol, declarations) + var internedName = getInternedName(symbol, node, declarations) forEach(sourceFiles, sourceFile => { cancellationToken.throwIfCancellationRequested(); @@ -4023,13 +4023,51 @@ module ts { return result; - function getDeclaredName(symbol: Symbol) { + function isImportOrExportSpecifierName(location: Node): boolean { + return location.parent && + (location.parent.kind === SyntaxKind.ImportSpecifier || location.parent.kind === SyntaxKind.ExportSpecifier) && + (location.parent).propertyName === location; + } + + function isImportOrExportSpecifierImportSymbol(symbol: Symbol) { + return (symbol.flags & SymbolFlags.Import) && forEach(symbol.declarations, declaration => { + return declaration.kind === SyntaxKind.ImportSpecifier || declaration.kind === SyntaxKind.ExportSpecifier; + }); + } + + function getDeclaredName(symbol: Symbol, location: Node) { + // Special case for function expressions, whose names are solely local to their bodies. + var functionExpression = forEach(symbol.declarations, d => d.kind === SyntaxKind.FunctionExpression ? d : undefined); + + // When a name gets interned into a SourceFile's 'identifiers' Map, + // its name is escaped and stored in the same way its symbol name/identifier + // name should be stored. Function expressions, however, are a special case, + // because despite sometimes having a name, the binder unconditionally binds them + // to a symbol with the name "__function". + if (functionExpression && functionExpression.name) { + var name = functionExpression.name.text; + } + + // If this is an export or import specifier it could have been renamed using the as syntax. + // if so we want to search for whatever under the cursor, the symbol is pointing to the alias (name) + // so check for the propertyName. + if (isImportOrExportSpecifierName(location)) { + return location.getText(); + } + var name = typeInfoResolver.symbolToString(symbol); return stripQuotes(name); } - function getInternedName(symbol: Symbol, declarations: Declaration[]): string { + function getInternedName(symbol: Symbol, location: Node, declarations: Declaration[]): string { + // If this is an export or import specifier it could have been renamed using the as syntax. + // if so we want to search for whatever under the cursor, the symbol is pointing to the alias (name) + // so check for the propertyName. + if (isImportOrExportSpecifierName(location)) { + return location.getText(); + } + // Special case for function expressions, whose names are solely local to their bodies. var functionExpression = forEach(declarations, d => d.kind === SyntaxKind.FunctionExpression ? d : undefined); @@ -4058,16 +4096,22 @@ module ts { function getSymbolScope(symbol: Symbol): Node { // If this is private property or method, the scope is the containing class - if (symbol.getFlags() && (SymbolFlags.Property | SymbolFlags.Method)) { + if (symbol.flags & (SymbolFlags.Property | SymbolFlags.Method)) { var privateDeclaration = forEach(symbol.getDeclarations(), d => (d.flags & NodeFlags.Private) ? d : undefined); if (privateDeclaration) { return getAncestor(privateDeclaration, SyntaxKind.ClassDeclaration); } } + // If the symbol is an import we would like to find it if we are looking for what it imports. + // So consider it visibile outside its declaration scope. + if (symbol.flags & SymbolFlags.Import) { + return undefined; + } + // if this symbol is visible from its parent container, e.g. exported, then bail out // if symbol correspond to the union property - bail out - if (symbol.parent || (symbol.getFlags() & SymbolFlags.UnionProperty)) { + if (symbol.parent || (symbol.flags & SymbolFlags.UnionProperty)) { return undefined; } @@ -4422,6 +4466,11 @@ module ts { // The search set contains at least the current symbol var result = [symbol]; + // If the symbol is an alias, add what it alaises to the list + if (isImportOrExportSpecifierImportSymbol(symbol)) { + result.push(typeInfoResolver.getAliasedSymbol(symbol)); + } + // If the location is in a context sensitive location (i.e. in an object literal) try // to get a contextual type for it, and add the property symbol from the contextual // type to the search set @@ -4498,6 +4547,13 @@ module ts { return true; } + // If the reference symbol is an alias, check if what it is aliasing is one of the search + // symbols. + if (isImportOrExportSpecifierImportSymbol(referenceSymbol) && + searchSymbols.indexOf(typeInfoResolver.getAliasedSymbol(referenceSymbol)) >= 0) { + return true; + } + // If the reference location is in an object literal, try to get the contextual type for the // object literal, lookup the property symbol in the contextual type, and use this symbol to // compare to our searchSymbol diff --git a/tests/cases/fourslash/findAllRefsOnImportAliases.ts b/tests/cases/fourslash/findAllRefsOnImportAliases.ts new file mode 100644 index 0000000000000..dbfab33aa8607 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsOnImportAliases.ts @@ -0,0 +1,29 @@ +/// + +//@Filename: a.ts +////export class /*1*/Class{ +////} + +//@Filename: b.ts +////import { /*2*/Class } from "a"; +//// +////var c = new /*3*/Class(); + +//@Filename: c.ts +////export { /*4*/Class } from "a"; + +goTo.file("a.ts"); +goTo.marker("1"); +verify.referencesCountIs(4); + +goTo.file("b.ts"); +goTo.marker("2"); +verify.referencesCountIs(4); + +goTo.marker("3"); +verify.referencesCountIs(4); + +goTo.file("c.ts"); +goTo.marker("4"); +verify.referencesCountIs(4); + diff --git a/tests/cases/fourslash/findAllRefsOnImportAliases2.ts b/tests/cases/fourslash/findAllRefsOnImportAliases2.ts new file mode 100644 index 0000000000000..dca6b13bbd276 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsOnImportAliases2.ts @@ -0,0 +1,31 @@ +/// + +//@Filename: a.ts +////export class /*1*/Class{ +////} + +//@Filename: b.ts +////import { /*2*/Class as /*3*/C2} from "a"; +//// +////var c = new C2(); + +//@Filename: c.ts +////export { /*4*/Class as /*5*/C3 } from "a"; + +goTo.file("a.ts"); +goTo.marker("1"); +verify.referencesCountIs(3); + +goTo.file("b.ts"); +goTo.marker("2"); +verify.referencesCountIs(3); + +goTo.marker("3"); +verify.referencesCountIs(2); + +goTo.file("c.ts"); +goTo.marker("4"); +verify.referencesCountIs(3); + +goTo.marker("5"); +verify.referencesCountIs(1); From 7b7d2b6006ec510fc391fc1a197647ad3382c622 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 24 Feb 2015 11:54:10 -0800 Subject: [PATCH 6/8] Support navigation bar for new import/export syntax --- src/services/navigationBar.ts | 45 ++++++++++++++++++- .../scriptLexicalStructureExports.ts | 18 ++++++++ .../scriptLexicalStructureImports.ts | 25 +++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 tests/cases/fourslash/scriptLexicalStructureExports.ts create mode 100644 tests/cases/fourslash/scriptLexicalStructureImports.ts diff --git a/src/services/navigationBar.ts b/src/services/navigationBar.ts index b254397f8b0cc..8bc02d7698b8f 100644 --- a/src/services/navigationBar.ts +++ b/src/services/navigationBar.ts @@ -50,6 +50,38 @@ module ts.NavigationBar { case SyntaxKind.ArrayBindingPattern: forEach((node).elements, visit); break; + + case SyntaxKind.ExportDeclaration: + // Handle named exports case e.g.: + // export {a, b as B} from "mod"; + if ((node).exportClause) { + forEach((node).exportClause.elements, visit); + } + break; + + case SyntaxKind.ImportDeclaration: + var importClause = (node).importClause; + if (importClause) { + // Handle default import case e.g.: + // import d from "mod"; + if (importClause.name) { + childNodes.push(importClause); + } + + // Handle named bindings in imports e.g.: + // import * as NS from "mod"; + // import {a, b as B} from "mod"; + if (importClause.namedBindings) { + if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { + childNodes.push(importClause.namedBindings); + } + else { + forEach((importClause.namedBindings).elements, visit); + } + } + } + break; + case SyntaxKind.BindingElement: case SyntaxKind.VariableDeclaration: if (isBindingPattern((node).name)) { @@ -62,7 +94,11 @@ module ts.NavigationBar { case SyntaxKind.InterfaceDeclaration: case SyntaxKind.ModuleDeclaration: case SyntaxKind.FunctionDeclaration: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ExportSpecifier: childNodes.push(node); + break; } } @@ -291,9 +327,16 @@ module ts.NavigationBar { else { return createItem(node, getTextOfNode(name), ts.ScriptElementKind.variableElement); } - + case SyntaxKind.Constructor: return createItem(node, "constructor", ts.ScriptElementKind.constructorImplementationElement); + + case SyntaxKind.ExportSpecifier: + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ImportClause: + case SyntaxKind.NamespaceImport: + return createItem(node, getTextOfNode((node).name), ts.ScriptElementKind.alias); } return undefined; diff --git a/tests/cases/fourslash/scriptLexicalStructureExports.ts b/tests/cases/fourslash/scriptLexicalStructureExports.ts new file mode 100644 index 0000000000000..f2a4adfa0d1d6 --- /dev/null +++ b/tests/cases/fourslash/scriptLexicalStructureExports.ts @@ -0,0 +1,18 @@ +/// + + +////export { {| "itemName": "a", "kind": "alias", "parentName": "" |}a } from "a"; +//// +////export { {| "itemName": "B", "kind": "alias", "parentName": "" |}b as B } from "a" +//// +////{| "itemName": "e", "kind": "alias", "parentName": "" |} export import e = require("a"); +//// +////export * from "a"; // no bindings here + +test.markers().forEach((marker) => { + if (marker.data) { + verify.getScriptLexicalStructureListContains(marker.data.itemName, marker.data.kind, marker.fileName, marker.data.parentName); + } +}); + +verify.getScriptLexicalStructureListCount(4); diff --git a/tests/cases/fourslash/scriptLexicalStructureImports.ts b/tests/cases/fourslash/scriptLexicalStructureImports.ts new file mode 100644 index 0000000000000..9d9e3e8b46860 --- /dev/null +++ b/tests/cases/fourslash/scriptLexicalStructureImports.ts @@ -0,0 +1,25 @@ +/// + + +////import {| "itemName": "d1", "kind": "alias", "parentName": "" |}d1 from "a"; +//// +////import { {| "itemName": "a", "kind": "alias", "parentName": "" |}a } from "a"; +//// +////import { {| "itemName": "B", "kind": "alias", "parentName": "" |}b as B } from "a" +//// +////import {| "itemName": "d2", "kind": "alias", "parentName": "" |}d2, +//// { {| "itemName": "c", "kind": "alias", "parentName": "" |}c, +//// {| "itemName": "D", "kind": "alias", "parentName": "" |} d as D } from "a" +//// +////{| "itemName": "e", "kind": "alias", "parentName": "" |}import e = require("a"); +//// +////import {| "itemName": "ns", "kind": "alias", "parentName": "" |}* as ns from "a"; + + +test.markers().forEach((marker) => { + if (marker.data) { + verify.getScriptLexicalStructureListContains(marker.data.itemName, marker.data.kind, marker.fileName, marker.data.parentName); + } +}); + +verify.getScriptLexicalStructureListCount(9); From 951f7cf31f977a23d7f893a8e549dd5ecc95498a Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 24 Feb 2015 12:24:41 -0800 Subject: [PATCH 7/8] Support navigateTo for new import/export syntax --- src/services/services.ts | 42 +++++++++++++++++++ tests/cases/fourslash/navigateItemsExports.ts | 20 +++++++++ tests/cases/fourslash/navigateItemsImports.ts | 25 +++++++++++ 3 files changed, 87 insertions(+) create mode 100644 tests/cases/fourslash/navigateItemsExports.ts create mode 100644 tests/cases/fourslash/navigateItemsImports.ts diff --git a/src/services/services.ts b/src/services/services.ts index 708869fddf548..be515abeb508f 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -802,6 +802,11 @@ module ts { case SyntaxKind.EnumDeclaration: case SyntaxKind.ModuleDeclaration: case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ExportSpecifier: + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ImportClause: + case SyntaxKind.NamespaceImport: case SyntaxKind.GetAccessor: case SyntaxKind.SetAccessor: case SyntaxKind.TypeLiteral: @@ -841,6 +846,37 @@ module ts { case SyntaxKind.PropertySignature: namedDeclarations.push(node); break; + + case SyntaxKind.ExportDeclaration: + // Handle named exports case e.g.: + // export {a, b as B} from "mod"; + if ((node).exportClause) { + forEach((node).exportClause.elements, visit); + } + break; + + case SyntaxKind.ImportDeclaration: + var importClause = (node).importClause; + if (importClause) { + // Handle default import case e.g.: + // import d from "mod"; + if (importClause.name) { + namedDeclarations.push(importClause); + } + + // Handle named bindings in imports e.g.: + // import * as NS from "mod"; + // import {a, b as B} from "mod"; + if (importClause.namedBindings) { + if (importClause.namedBindings.kind === SyntaxKind.NamespaceImport) { + namedDeclarations.push(importClause.namedBindings); + } + else { + forEach((importClause.namedBindings).elements, visit); + } + } + } + break; } }); @@ -2010,6 +2046,12 @@ module ts { case SyntaxKind.TypeParameter: return ScriptElementKind.typeParameterElement; case SyntaxKind.EnumMember: return ScriptElementKind.variableElement; case SyntaxKind.Parameter: return (node.flags & NodeFlags.AccessibilityModifier) ? ScriptElementKind.memberVariableElement : ScriptElementKind.parameterElement; + case SyntaxKind.ImportEqualsDeclaration: + case SyntaxKind.ImportSpecifier: + case SyntaxKind.ImportClause: + case SyntaxKind.ExportSpecifier: + case SyntaxKind.NamespaceImport: + return ScriptElementKind.alias; } return ScriptElementKind.unknown; } diff --git a/tests/cases/fourslash/navigateItemsExports.ts b/tests/cases/fourslash/navigateItemsExports.ts new file mode 100644 index 0000000000000..646d557aace4a --- /dev/null +++ b/tests/cases/fourslash/navigateItemsExports.ts @@ -0,0 +1,20 @@ +/// + +////export { {| "itemName": "a", "kind": "alias", "parentName": "" |}a } from "a"; +//// +////export { {| "itemName": "B", "kind": "alias", "parentName": "" |}b as B } from "a"; +//// +////export { {| "itemName": "c", "kind": "alias", "parentName": "" |}c, +//// {| "itemName": "D", "kind": "alias", "parentName": "" |}d as D } from "a"; +//// +////{| "itemName": "f", "kind": "alias", "parentName": "" |}export import f = require("a"); + +test.markers().forEach(marker => { + verify.navigationItemsListContains( + marker.data.itemName, + marker.data.kind, + marker.data.itemName, + "exact", + marker.fileName, + marker.data.parentName); +}); \ No newline at end of file diff --git a/tests/cases/fourslash/navigateItemsImports.ts b/tests/cases/fourslash/navigateItemsImports.ts new file mode 100644 index 0000000000000..8ac3e0006396a --- /dev/null +++ b/tests/cases/fourslash/navigateItemsImports.ts @@ -0,0 +1,25 @@ +/// + +////import {| "itemName": "ns", "kind": "alias", "parentName": "" |}* as ns from "a"; +//// +////import { {| "itemName": "a", "kind": "alias", "parentName": "" |}a } from "a"; +//// +////import { {| "itemName": "B", "kind": "alias", "parentName": "" |}b as B } from "a"; +//// +////import { {| "itemName": "c", "kind": "alias", "parentName": "" |}c, +//// {| "itemName": "D", "kind": "alias", "parentName": "" |}d as D } from "a"; +//// +////import {| "itemName": "d1", "kind": "alias", "parentName": "" |}d1, { +//// {| "itemName": "e", "kind": "alias", "parentName": "" |}e } from "a"; +//// +////{| "itemName": "f", "kind": "alias", "parentName": "" |}import f = require("a"); + +test.markers().forEach(marker => { + verify.navigationItemsListContains( + marker.data.itemName, + marker.data.kind, + marker.data.itemName, + "exact", + marker.fileName, + marker.data.parentName); +}); \ No newline at end of file From bc4057af858e0a50c4dffab9286eb24cc7114230 Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 24 Feb 2015 13:03:14 -0800 Subject: [PATCH 8/8] breakpoint support for new import/export syntax --- src/services/breakpoints.ts | 10 +++++- .../reference/bpSpan_exports.baseline | 17 +++++++++ .../reference/bpSpan_imports.baseline | 35 +++++++++++++++++++ .../fourslash/breakpointValidationExports.ts | 9 +++++ .../fourslash/breakpointValidationImports.ts | 12 +++++++ 5 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/bpSpan_exports.baseline create mode 100644 tests/baselines/reference/bpSpan_imports.baseline create mode 100644 tests/cases/fourslash/breakpointValidationExports.ts create mode 100644 tests/cases/fourslash/breakpointValidationImports.ts diff --git a/src/services/breakpoints.ts b/src/services/breakpoints.ts index a4943705e72db..59c4e7168906c 100644 --- a/src/services/breakpoints.ts +++ b/src/services/breakpoints.ts @@ -178,7 +178,15 @@ module ts.BreakpointResolver { case SyntaxKind.ImportEqualsDeclaration: // import statement without including semicolon - return textSpan(node,(node).moduleReference); + return textSpan(node, (node).moduleReference); + + case SyntaxKind.ImportDeclaration: + // import statement without including semicolon + return textSpan(node, (node).moduleSpecifier); + + case SyntaxKind.ExportDeclaration: + // import statement without including semicolon + return textSpan(node, (node).moduleSpecifier); case SyntaxKind.ModuleDeclaration: // span on complete module if it is instantiated diff --git a/tests/baselines/reference/bpSpan_exports.baseline b/tests/baselines/reference/bpSpan_exports.baseline new file mode 100644 index 0000000000000..1b09fb75a2f48 --- /dev/null +++ b/tests/baselines/reference/bpSpan_exports.baseline @@ -0,0 +1,17 @@ + +1 >export * from "a"; + + ~~~~~~~~~~~~~~~~~~~ => Pos: (0 to 18) SpanInfo: {"start":0,"length":17} + >export * from "a" + >:=> (line 1, col 0) to (line 1, col 17) +-------------------------------- +2 >export {a as A} from "a"; + + ~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (19 to 44) SpanInfo: {"start":19,"length":24} + >export {a as A} from "a" + >:=> (line 2, col 0) to (line 2, col 24) +-------------------------------- +3 >export import e = require("a"); + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (45 to 75) SpanInfo: {"start":45,"length":30} + >export import e = require("a") + >:=> (line 3, col 0) to (line 3, col 30) \ No newline at end of file diff --git a/tests/baselines/reference/bpSpan_imports.baseline b/tests/baselines/reference/bpSpan_imports.baseline new file mode 100644 index 0000000000000..c59f9faf9041a --- /dev/null +++ b/tests/baselines/reference/bpSpan_imports.baseline @@ -0,0 +1,35 @@ + +1 >import * as NS from "a"; + + ~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (0 to 24) SpanInfo: {"start":0,"length":23} + >import * as NS from "a" + >:=> (line 1, col 0) to (line 1, col 23) +-------------------------------- +2 >import {a as A} from "a"; + + ~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (25 to 50) SpanInfo: {"start":25,"length":24} + >import {a as A} from "a" + >:=> (line 2, col 0) to (line 2, col 24) +-------------------------------- +3 > import d from "a"; + + ~~~~~~~~~~~~~~~~~~~~ => Pos: (51 to 70) SpanInfo: {"start":52,"length":17} + >import d from "a" + >:=> (line 3, col 1) to (line 3, col 18) +-------------------------------- +4 >import d2, {c, d as D} from "a"; + + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (71 to 103) SpanInfo: {"start":71,"length":31} + >import d2, {c, d as D} from "a" + >:=> (line 4, col 0) to (line 4, col 31) +-------------------------------- +5 >import "a"; + + ~~~~~~~~~~~~ => Pos: (104 to 115) SpanInfo: {"start":104,"length":10} + >import "a" + >:=> (line 5, col 0) to (line 5, col 10) +-------------------------------- +6 >import e = require("a"); + ~~~~~~~~~~~~~~~~~~~~~~~~ => Pos: (116 to 139) SpanInfo: {"start":116,"length":23} + >import e = require("a") + >:=> (line 6, col 0) to (line 6, col 23) \ No newline at end of file diff --git a/tests/cases/fourslash/breakpointValidationExports.ts b/tests/cases/fourslash/breakpointValidationExports.ts new file mode 100644 index 0000000000000..092d4fdc143b5 --- /dev/null +++ b/tests/cases/fourslash/breakpointValidationExports.ts @@ -0,0 +1,9 @@ +/// + +// @BaselineFile: bpSpan_exports.baseline +// @Filename: bpSpan_exports.ts +////export * from "a"; +////export {a as A} from "a"; +////export import e = require("a"); + +verify.baselineCurrentFileBreakpointLocations(); \ No newline at end of file diff --git a/tests/cases/fourslash/breakpointValidationImports.ts b/tests/cases/fourslash/breakpointValidationImports.ts new file mode 100644 index 0000000000000..c2ec25a109652 --- /dev/null +++ b/tests/cases/fourslash/breakpointValidationImports.ts @@ -0,0 +1,12 @@ +/// + +// @BaselineFile: bpSpan_imports.baseline +// @Filename: bpSpan_imports.ts +////import * as NS from "a"; +////import {a as A} from "a"; +//// import d from "a"; +////import d2, {c, d as D} from "a"; +////import "a"; +////import e = require("a"); + +verify.baselineCurrentFileBreakpointLocations(); \ No newline at end of file