Added rules for spacing around decorators, computing the undecorated start line of a node

This commit is contained in:
Ron Buckton 2015-04-07 16:15:02 -07:00
parent 189f07ae7f
commit 1a1bb34864
5 changed files with 147 additions and 13 deletions

View File

@ -150,14 +150,20 @@ module ts {
return !nodeIsMissing(node);
}
export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile): number {
export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile, skipDecorators?: boolean): number {
// With nodes that have no width (i.e. 'Missing' nodes), we actually *don't*
// want to skip trivia because this will launch us forward to the next token.
if (nodeIsMissing(node)) {
return node.pos;
}
return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos);
let pos = node.pos;
if (skipDecorators && node.decorators) {
// Skip past decorators
pos = node.decorators.end;
}
return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, pos);
}
export function getSourceTextOfNodeFromSourceFile(sourceFile: SourceFile, node: Node): string {

View File

@ -328,8 +328,13 @@ module ts.formatting {
if (formattingScanner.isOnToken()) {
let startLine = sourceFile.getLineAndCharacterOfPosition(enclosingNode.getStart(sourceFile)).line;
let undecoratedStartLine = startLine;
if (enclosingNode.decorators) {
undecoratedStartLine = sourceFile.getLineAndCharacterOfPosition(enclosingNode.getStart(sourceFile, /*skipDecorators*/ true)).line;
}
let delta = getOwnOrInheritedDelta(enclosingNode, options, sourceFile);
processNode(enclosingNode, enclosingNode, startLine, initialIndentation, delta);
processNode(enclosingNode, enclosingNode, startLine, undecoratedStartLine, initialIndentation, delta);
}
formattingScanner.close();
@ -500,7 +505,7 @@ module ts.formatting {
}
}
function processNode(node: Node, contextNode: Node, nodeStartLine: number, indentation: number, delta: number) {
function processNode(node: Node, contextNode: Node, nodeStartLine: number, undecoratedNodeStartLine: number, indentation: number, delta: number) {
if (!rangeOverlapsWithStartEnd(originalRange, node.getStart(sourceFile), node.getEnd())) {
return;
}
@ -526,7 +531,7 @@ module ts.formatting {
forEachChild(
node,
child => {
processChildNode(child, /*inheritedIndentation*/ Constants.Unknown, node, nodeDynamicIndentation, nodeStartLine, /*isListElement*/ false)
processChildNode(child, /*inheritedIndentation*/ Constants.Unknown, node, nodeDynamicIndentation, nodeStartLine, undecoratedNodeStartLine, /*isListElement*/ false)
},
(nodes: NodeArray<Node>) => {
processChildNodes(nodes, node, nodeStartLine, nodeDynamicIndentation);
@ -547,11 +552,17 @@ module ts.formatting {
parent: Node,
parentDynamicIndentation: DynamicIndentation,
parentStartLine: number,
undecoratedParentStartLine: number,
isListItem: boolean): number {
let childStartPos = child.getStart(sourceFile);
let childStart = sourceFile.getLineAndCharacterOfPosition(childStartPos);
let childStartLine = sourceFile.getLineAndCharacterOfPosition(childStartPos).line;
let undecoratedChildStartLine = childStartLine;
if (child.decorators) {
undecoratedChildStartLine = sourceFile.getLineAndCharacterOfPosition(child.getStart(sourceFile, /*skipDecorators*/ true)).line;
}
// if child is a list item - try to get its indentation
let childIndentationAmount = Constants.Unknown;
@ -594,9 +605,10 @@ module ts.formatting {
return inheritedIndentation;
}
let childIndentation = computeIndentation(child, childStart.line, childIndentationAmount, node, parentDynamicIndentation, parentStartLine);
let effectiveParentStartLine = child.kind === SyntaxKind.Decorator ? childStartLine : undecoratedParentStartLine;
let childIndentation = computeIndentation(child, childStartLine, childIndentationAmount, node, parentDynamicIndentation, effectiveParentStartLine);
processNode(child, childContextNode, childStart.line, childIndentation.indentation, childIndentation.delta);
processNode(child, childContextNode, childStartLine, undecoratedChildStartLine, childIndentation.indentation, childIndentation.delta);
childContextNode = node;
@ -640,7 +652,7 @@ module ts.formatting {
let inheritedIndentation = Constants.Unknown;
for (let child of nodes) {
inheritedIndentation = processChildNode(child, inheritedIndentation, node, listDynamicIndentation, startLine, /*isListElement*/ true)
inheritedIndentation = processChildNode(child, inheritedIndentation, node, listDynamicIndentation, startLine, startLine, /*isListElement*/ true)
}
if (listEndToken !== SyntaxKind.Unknown) {

View File

@ -208,6 +208,10 @@ module ts.formatting {
public SpaceAfterAnonymousFunctionKeyword: Rule;
public NoSpaceAfterAnonymousFunctionKeyword: Rule;
// Insert space after @ in decorator
public SpaceBeforeAt: Rule;
public NoSpaceAfterAt: Rule;
constructor() {
///
/// Common Rules
@ -344,6 +348,10 @@ module ts.formatting {
// Remove spaces in empty interface literals. e.g.: x: {}
this.NoSpaceBetweenEmptyInterfaceBraceBrackets = new Rule(RuleDescriptor.create1(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext, Rules.IsObjectTypeContext), RuleAction.Delete));
// decorators
this.SpaceBeforeAt = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.AtToken), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Space));
this.NoSpaceAfterAt = new Rule(RuleDescriptor.create3(SyntaxKind.AtToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsSameLineTokenContext), RuleAction.Delete));
// These rules are higher in priority than user-configurable rules.
this.HighPriorityCommonRules =
[
@ -381,7 +389,9 @@ module ts.formatting {
this.NoSpaceBetweenCloseParenAndAngularBracket,
this.NoSpaceAfterOpenAngularBracket,
this.NoSpaceBeforeCloseAngularBracket,
this.NoSpaceAfterCloseAngularBracket
this.NoSpaceAfterCloseAngularBracket,
this.SpaceBeforeAt,
this.NoSpaceAfterAt,
];
// These rules are lower in priority than user-configurable rules.

View File

@ -19,7 +19,7 @@ module ts {
getChildCount(sourceFile?: SourceFile): number;
getChildAt(index: number, sourceFile?: SourceFile): Node;
getChildren(sourceFile?: SourceFile): Node[];
getStart(sourceFile?: SourceFile): number;
getStart(sourceFile?: SourceFile, skipDecorators?: boolean): number;
getFullStart(): number;
getEnd(): number;
getWidth(sourceFile?: SourceFile): number;
@ -149,8 +149,8 @@ module ts {
return getSourceFileOfNode(this);
}
public getStart(sourceFile?: SourceFile): number {
return getTokenPosOfNode(this, sourceFile);
public getStart(sourceFile?: SourceFile, skipDecorators?: boolean): number {
return getTokenPosOfNode(this, sourceFile, skipDecorators);
}
public getFullStart(): number {

View File

@ -0,0 +1,106 @@
/// <reference path='fourslash.ts' />
/////*1*/ @ decorator1
/////*2*/ @ decorator2
/////*3*/ @decorator3
/////*4*/ @ decorator4 @ decorator5
/////*5*/class C {
/////*6*/ @ decorator6
/////*7*/ @ decorator7
/////*8*/ @decorator8
/////*9*/ method1() { }
////
/////*10*/ @ decorator9 @ decorator10 @decorator11 method2() { }
////
//// method3(
/////*11*/ @ decorator12
/////*12*/ @ decorator13
/////*13*/ @decorator14
/////*14*/ x) { }
////
//// method4(
/////*15*/ @ decorator15 @ decorator16 @decorator17 x) { }
////
/////*16*/ @ decorator18
/////*17*/ @ decorator19
/////*18*/ @decorator20
/////*19*/ ["computed1"]() { }
////
/////*20*/ @ decorator21 @ decorator22 @decorator23 ["computed2"]() { }
////
/////*21*/ @ decorator24
/////*22*/ @ decorator25
/////*23*/ @decorator26
/////*24*/ get accessor1() { }
////
/////*25*/ @ decorator27 @ decorator28 @decorator29 get accessor2() { }
////
/////*26*/ @ decorator30
/////*27*/ @ decorator31
/////*28*/ @decorator32
/////*29*/ property1;
////
/////*30*/ @ decorator33 @ decorator34 @decorator35 property2;
////}
format.document();
goTo.marker("1");
verify.currentLineContentIs("@decorator1");
goTo.marker("2");
verify.currentLineContentIs("@decorator2");
goTo.marker("3");
verify.currentLineContentIs("@decorator3");
goTo.marker("4");
verify.currentLineContentIs("@decorator4 @decorator5");
goTo.marker("5");
verify.currentLineContentIs("class C {");
goTo.marker("6");
verify.currentLineContentIs(" @decorator6");
goTo.marker("7");
verify.currentLineContentIs(" @decorator7");
goTo.marker("8");
verify.currentLineContentIs(" @decorator8");
goTo.marker("9");
verify.currentLineContentIs(" method1() { }");
goTo.marker("10");
verify.currentLineContentIs(" @decorator9 @decorator10 @decorator11 method2() { }");
goTo.marker("11");
verify.currentLineContentIs(" @decorator12");
goTo.marker("12");
verify.currentLineContentIs(" @decorator13");
goTo.marker("13");
verify.currentLineContentIs(" @decorator14");
goTo.marker("14");
verify.currentLineContentIs(" x) { }");
goTo.marker("15");
verify.currentLineContentIs(" @decorator15 @decorator16 @decorator17 x) { }");
goTo.marker("16");
verify.currentLineContentIs(" @decorator18");
goTo.marker("17");
verify.currentLineContentIs(" @decorator19");
goTo.marker("18");
verify.currentLineContentIs(" @decorator20");
goTo.marker("19");
verify.currentLineContentIs(" [\"computed1\"]() { }");
goTo.marker("20");
verify.currentLineContentIs(" @decorator21 @decorator22 @decorator23 [\"computed2\"]() { }");
goTo.marker("21");
verify.currentLineContentIs(" @decorator24");
goTo.marker("22");
verify.currentLineContentIs(" @decorator25");
goTo.marker("23");
verify.currentLineContentIs(" @decorator26");
goTo.marker("24");
verify.currentLineContentIs(" get accessor1() { }");
goTo.marker("25");
verify.currentLineContentIs(" @decorator27 @decorator28 @decorator29 get accessor2() { }");
goTo.marker("26");
verify.currentLineContentIs(" @decorator30");
goTo.marker("27");
verify.currentLineContentIs(" @decorator31");
goTo.marker("28");
verify.currentLineContentIs(" @decorator32");
goTo.marker("29");
verify.currentLineContentIs(" property1;");
goTo.marker("30");
verify.currentLineContentIs(" @decorator33 @decorator34 @decorator35 property2;");