Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 10 additions & 8 deletions src/services/formatting/formatting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -488,14 +488,16 @@ namespace ts.formatting {
// open and close brace, 'else' and 'while' (in do statement) tokens has indentation of the parent
case SyntaxKind.OpenBraceToken:
case SyntaxKind.CloseBraceToken:
case SyntaxKind.OpenBracketToken:
case SyntaxKind.CloseBracketToken:
case SyntaxKind.OpenParenToken:
case SyntaxKind.CloseParenToken:
case SyntaxKind.ElseKeyword:
case SyntaxKind.WhileKeyword:
case SyntaxKind.AtToken:
return indentation;
case SyntaxKind.OpenBracketToken:
case SyntaxKind.CloseBracketToken:
return (container.kind === SyntaxKind.MappedType) ?
indentation + getEffectiveDelta(delta, container) : indentation;
default:
// if token line equals to the line of containing node (this is a first token in the node) - use node indentation
return nodeStartLine !== line ? indentation + getEffectiveDelta(delta, container) : indentation;
Expand Down Expand Up @@ -566,7 +568,7 @@ namespace ts.formatting {
if (tokenInfo.token.end > node.end) {
break;
}
consumeTokenAndAdvanceScanner(tokenInfo, node, nodeDynamicIndentation);
consumeTokenAndAdvanceScanner(tokenInfo, node, nodeDynamicIndentation, node);
}

function processChildNode(
Expand Down Expand Up @@ -617,7 +619,7 @@ namespace ts.formatting {
break;
}

consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation);
consumeTokenAndAdvanceScanner(tokenInfo, node, parentDynamicIndentation, node);
}

if (!formattingScanner.isOnToken()) {
Expand Down Expand Up @@ -673,11 +675,11 @@ namespace ts.formatting {
computeIndentation(tokenInfo.token, startLine, Constants.Unknown, parent, parentDynamicIndentation, parentStartLine);

listDynamicIndentation = getDynamicIndentation(parent, parentStartLine, indentation.indentation, indentation.delta);
consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation);
consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation, parent);
}
else {
// consume any tokens that precede the list as child elements of 'node' using its indentation scope
consumeTokenAndAdvanceScanner(tokenInfo, parent, parentDynamicIndentation);
consumeTokenAndAdvanceScanner(tokenInfo, parent, parentDynamicIndentation, parent);
}
}
}
Expand All @@ -697,13 +699,13 @@ namespace ts.formatting {
// without this check close paren will be interpreted as list end token for function expression which is wrong
if (tokenInfo.token.kind === listEndToken && rangeContainsRange(parent, tokenInfo.token)) {
// consume list end token
consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation);
consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation, parent);
}
}
}
}

function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation, container?: Node): void {
function consumeTokenAndAdvanceScanner(currentTokenInfo: TokenInfo, parent: Node, dynamicIndentation: DynamicIndentation, container: Node): void {
Debug.assert(rangeContainsRange(parent, currentTokenInfo.token));

const lastTriviaWasNewLine = formattingScanner.lastTrailingTriviaWasNewLine();
Expand Down
5 changes: 4 additions & 1 deletion src/services/formatting/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,7 +362,7 @@ 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.ReadonlyKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword, SyntaxKind.TypeKeyword, SyntaxKind.FromKeyword]), Shared.TokenRange.Any), 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.ReadonlyKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword, SyntaxKind.TypeKeyword, SyntaxKind.FromKeyword, SyntaxKind.KeyOfKeyword]), 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" {
Expand Down Expand Up @@ -578,6 +578,8 @@ namespace ts.formatting {
return context.currentTokenSpan.kind === SyntaxKind.EqualsToken || context.nextTokenSpan.kind === SyntaxKind.EqualsToken;
// "in" keyword in for (let x in []) { }
case SyntaxKind.ForInStatement:
// "in" keyword in [P in keyof T]: T[P]
case SyntaxKind.TypeParameter:
return context.currentTokenSpan.kind === SyntaxKind.InKeyword || context.nextTokenSpan.kind === SyntaxKind.InKeyword;
// Technically, "of" is not a binary operator, but format it the same way as "in"
case SyntaxKind.ForOfStatement:
Expand Down Expand Up @@ -832,6 +834,7 @@ namespace ts.formatting {
switch (parent.kind) {
case SyntaxKind.TypeReference:
case SyntaxKind.TypeAssertionExpression:
case SyntaxKind.TypeAliasDeclaration:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
case SyntaxKind.InterfaceDeclaration:
Expand Down
1 change: 1 addition & 0 deletions src/services/formatting/smartIndenter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ namespace ts.formatting {
case SyntaxKind.ModuleBlock:
case SyntaxKind.ObjectLiteralExpression:
case SyntaxKind.TypeLiteral:
case SyntaxKind.MappedType:
case SyntaxKind.TupleType:
case SyntaxKind.CaseBlock:
case SyntaxKind.DefaultClause:
Expand Down
12 changes: 12 additions & 0 deletions tests/cases/fourslash/formattingMappedType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/// <reference path='fourslash.ts' />

/////*generic*/type t < T > = {
/////*map*/ [ P in keyof T ] : T [ P ]
////};


format.document();
goTo.marker("generic");
verify.currentLineContentIs("type t<T> = {");
goTo.marker("map");
verify.currentLineContentIs(" [P in keyof T]: T[P]");