mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-02-05 16:38:05 -06:00
Added rules for spacing around decorators, computing the undecorated start line of a node
This commit is contained in:
parent
189f07ae7f
commit
1a1bb34864
@ -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 {
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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 {
|
||||
|
||||
106
tests/cases/fourslash/formattingDecorators.ts
Normal file
106
tests/cases/fourslash/formattingDecorators.ts
Normal 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;");
|
||||
Loading…
x
Reference in New Issue
Block a user