Skip to content

Commit

Permalink
Merge pull request #4609 from SaschaNaz/fixExportImportFormatting
Browse files Browse the repository at this point in the history
Fix named export/import formatting
  • Loading branch information
mhegazy authored Jun 27, 2016
2 parents b2bc91b + a8ac0ef commit cc1226c
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 3 deletions.
12 changes: 9 additions & 3 deletions src/services/formatting/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ namespace ts.formatting {
this.SpaceBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext, Rules.IsBeforeBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);

// Place a space before open brace in a TypeScript declaration that has braces as children (class, module, enum, etc)
this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.ClassKeyword]);
this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.ClassKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ImportKeyword]);
this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsTypeScriptDeclWithBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);

// Place a space before open brace in a control flow construct
Expand Down Expand Up @@ -338,8 +338,8 @@ namespace ts.formatting {
this.NoSpaceAfterModuleImport = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.ModuleKeyword, SyntaxKind.RequireKeyword]), SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));

// Add a space around certain TypeScript keywords
this.SpaceAfterCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.AbstractKeyword, SyntaxKind.ClassKeyword, SyntaxKind.DeclareKeyword, SyntaxKind.DefaultKeyword, SyntaxKind.EnumKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ExtendsKeyword, SyntaxKind.GetKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.ImportKeyword, SyntaxKind.InterfaceKeyword, SyntaxKind.ModuleKeyword, SyntaxKind.NamespaceKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.PublicKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword, SyntaxKind.TypeKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
this.SpaceBeforeCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.ExtendsKeyword, SyntaxKind.ImplementsKeyword])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
this.SpaceAfterCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.AbstractKeyword, SyntaxKind.ClassKeyword, SyntaxKind.DeclareKeyword, SyntaxKind.DefaultKeyword, SyntaxKind.EnumKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ExtendsKeyword, SyntaxKind.GetKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.ImportKeyword, SyntaxKind.InterfaceKeyword, SyntaxKind.ModuleKeyword, SyntaxKind.NamespaceKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.PublicKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword, SyntaxKind.TypeKeyword, SyntaxKind.FromKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
this.SpaceBeforeCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.ExtendsKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.FromKeyword])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));

// Treat string literals in module names as identifiers, and add a space between the literal and the opening Brace braces, e.g.: module "m2" {
this.SpaceAfterModuleName = new Rule(RuleDescriptor.create1(SyntaxKind.StringLiteral, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsModuleDeclContext), RuleAction.Space));
Expand Down Expand Up @@ -514,6 +514,8 @@ namespace ts.formatting {
case SyntaxKind.BinaryExpression:
case SyntaxKind.ConditionalExpression:
case SyntaxKind.AsExpression:
case SyntaxKind.ExportSpecifier:
case SyntaxKind.ImportSpecifier:
case SyntaxKind.TypePredicate:
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
Expand Down Expand Up @@ -650,6 +652,10 @@ namespace ts.formatting {
case SyntaxKind.EnumDeclaration:
case SyntaxKind.TypeLiteral:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ExportDeclaration:
case SyntaxKind.NamedExports:
case SyntaxKind.ImportDeclaration:
case SyntaxKind.NamedImports:
return true;
}

Expand Down
8 changes: 8 additions & 0 deletions src/services/formatting/smartIndenter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -466,7 +466,10 @@ namespace ts.formatting {
case SyntaxKind.ParenthesizedType:
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.AwaitExpression:
case SyntaxKind.NamedExports:
case SyntaxKind.NamedImports:
case SyntaxKind.ExportSpecifier:
case SyntaxKind.ImportSpecifier:
return true;
}
return false;
Expand All @@ -490,6 +493,11 @@ namespace ts.formatting {
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
return childKind !== SyntaxKind.Block;
case SyntaxKind.ExportDeclaration:
return childKind !== SyntaxKind.NamedExports;
case SyntaxKind.ImportDeclaration:
return childKind !== SyntaxKind.ImportClause ||
(<ImportClause>child).namedBindings.kind !== SyntaxKind.NamedImports;
case SyntaxKind.JsxElement:
return childKind !== SyntaxKind.JsxClosingElement;
}
Expand Down
6 changes: 6 additions & 0 deletions src/services/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ namespace ts {
case SyntaxKind.Block:
case SyntaxKind.ModuleBlock:
case SyntaxKind.CaseBlock:
case SyntaxKind.NamedImports:
case SyntaxKind.NamedExports:
return nodeEndsWith(n, SyntaxKind.CloseBraceToken, sourceFile);
case SyntaxKind.CatchClause:
return isCompletedNode((<CatchClause>n).block, sourceFile);
Expand Down Expand Up @@ -156,6 +158,10 @@ namespace ts {
case SyntaxKind.TemplateSpan:
return nodeIsPresent((<TemplateSpan>n).literal);

case SyntaxKind.ExportDeclaration:
case SyntaxKind.ImportDeclaration:
return nodeIsPresent((<ExportDeclaration | ImportDeclaration>n).moduleSpecifier);

case SyntaxKind.PrefixUnaryExpression:
return isCompletedNode((<PrefixUnaryExpression>n).operand, sourceFile);
case SyntaxKind.BinaryExpression:
Expand Down
81 changes: 81 additions & 0 deletions tests/cases/fourslash/formatNamedExportImport.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/// <reference path="fourslash.ts"/>

/////*selectionStart*/
////export { x, y as yy, z } from "foo"/*export1*/
////export{x, y as yy, z}from"bar"/*export2*/
////
////export
/////*exportOpenBrace*/{x,/*exportSpecifier1*/
////y as yy, z/*exportSpecifier2*/ }/*exportCloseBrace*/
//// from/*fromKeywordAutoformat*/
/////*fromKeywordIndent*/
////"foo"/*exportDir*/
////
////import {x, y as yy, z}from "baz"/*import1*/
////
////import/*importOpenBrace*/{x,/*importSpecifier1*/
////y
////as yy,/*importSpecifier2*/
////z}/*importCloseBrace*/
////from "wow"/*importDir*/
/////*selectionEnd*/
////
////export/*formatOnEnter*/{/*formatOnEnterOpenBrace*/
/////*differentLineIndent*/x/*differentLineAutoformat*/
////} from "abc"
////
////export {
/////*incompleteExportDeclIndent*/
/////*incompleteExportDeclIndent2*/

format.selection("selectionStart", "selectionEnd");

goTo.marker("export1");
verify.currentLineContentIs('export { x, y as yy, z } from "foo"');
goTo.marker("export2");
verify.currentLineContentIs('export { x, y as yy, z } from "bar"');

goTo.marker("exportOpenBrace");
verify.currentLineContentIs("export {");
goTo.marker("exportSpecifier1");
verify.currentLineContentIs(" x,");
goTo.marker("exportSpecifier2");
verify.currentLineContentIs(" y as yy, z");
goTo.marker("exportCloseBrace");
verify.currentLineContentIs("}");
goTo.marker("fromKeywordAutoformat");
verify.currentLineContentIs(" from");
goTo.marker("fromKeywordIndent");
verify.indentationIs(4);
goTo.marker("exportDir");
verify.currentLineContentIs(' "foo"');

goTo.marker("import1");
verify.currentLineContentIs('import { x, y as yy, z } from "baz"');

goTo.marker("importOpenBrace");
verify.currentLineContentIs("import {");
goTo.marker("importSpecifier1");
verify.currentLineContentIs(" x,");
goTo.marker("importSpecifier2");
verify.currentLineContentIs(" as yy,");
goTo.marker("importCloseBrace");
verify.currentLineContentIs("}");
goTo.marker("importDir");
verify.currentLineContentIs(' from "wow"');

goTo.marker("formatOnEnter");
edit.insertLine('');
goTo.marker("formatOnEnterOpenBrace");
verify.currentLineContentIs("{");
goTo.marker("differentLineIndent");
verify.indentationIs(4);
edit.insertLine('');
goTo.marker("differentLineAutoformat");
verify.currentLineContentIs(" x");

goTo.marker("incompleteExportDeclIndent")
verify.indentationIs(4);
edit.insert("} from");
goTo.marker("incompleteExportDeclIndent2");
verify.indentationIs(4);

0 comments on commit cc1226c

Please sign in to comment.