From 1a1bb34864d703d74615f2dcc9364c09330fe389 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 7 Apr 2015 16:15:02 -0700 Subject: [PATCH 1/3] Added rules for spacing around decorators, computing the undecorated start line of a node --- src/compiler/utilities.ts | 10 +- src/services/formatting/formatting.ts | 26 +++-- src/services/formatting/rules.ts | 12 +- src/services/services.ts | 6 +- tests/cases/fourslash/formattingDecorators.ts | 106 ++++++++++++++++++ 5 files changed, 147 insertions(+), 13 deletions(-) create mode 100644 tests/cases/fourslash/formattingDecorators.ts diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index e3efd12de0a0c..30f392e5ded2a 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -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 { diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 6a5ed25459e9d..ddf2f4cad27b7 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -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) => { 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) { diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index 7d3509ef495f3..4319f4bf311ce 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -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. diff --git a/src/services/services.ts b/src/services/services.ts index 86c323f24bfbe..042e2f4f01e1e 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -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 { diff --git a/tests/cases/fourslash/formattingDecorators.ts b/tests/cases/fourslash/formattingDecorators.ts new file mode 100644 index 0000000000000..9fc63d9d47bb6 --- /dev/null +++ b/tests/cases/fourslash/formattingDecorators.ts @@ -0,0 +1,106 @@ +/// + +/////*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;"); \ No newline at end of file From eec39c2fc50fdeee05b385e8c83fd54992e03d87 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Tue, 7 Apr 2015 17:23:52 -0700 Subject: [PATCH 2/3] Additional rule for spacing between decorator on same line as its declaration --- src/services/formatting/rules.ts | 25 +++++++++++++++++++ .../reference/APISample_linter.types | 4 +-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index 4319f4bf311ce..ac3d7fe678307 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -211,6 +211,7 @@ module ts.formatting { // Insert space after @ in decorator public SpaceBeforeAt: Rule; public NoSpaceAfterAt: Rule; + public SpaceAfterDecorator: Rule; constructor() { /// @@ -351,6 +352,7 @@ module ts.formatting { // 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)); + this.SpaceAfterDecorator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.ExportKeyword, SyntaxKind.DefaultKeyword, SyntaxKind.ClassKeyword, SyntaxKind.StaticKeyword, SyntaxKind.PublicKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.GetKeyword, SyntaxKind.SetKeyword, SyntaxKind.OpenBracketToken, SyntaxKind.AsteriskToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsEndOfDecoratorContextOnSameLine), RuleAction.Space)); // These rules are higher in priority than user-configurable rules. this.HighPriorityCommonRules = @@ -392,6 +394,7 @@ module ts.formatting { this.NoSpaceAfterCloseAngularBracket, this.SpaceBeforeAt, this.NoSpaceAfterAt, + this.SpaceAfterDecorator, ]; // These rules are lower in priority than user-configurable rules. @@ -659,6 +662,28 @@ module ts.formatting { return context.TokensAreOnSameLine(); } + static IsEndOfDecoratorContextOnSameLine(context: FormattingContext): boolean { + return context.TokensAreOnSameLine() && + context.contextNode.decorators && + Rules.NodeIsInDecoratorContext(context.currentTokenParent) && + !Rules.NodeIsInDecoratorContext(context.nextTokenParent); + } + + static NodeIsInDecoratorContext(node: Node): boolean { + if (node.parserContextFlags & ParserContextFlags.Decorator) { + return true; + } + while (node) { + if (isExpression(node)) { + node = node.parent; + } + else { + return node.kind === SyntaxKind.Decorator; + } + } + return false; + } + static IsStartOfVariableDeclarationList(context: FormattingContext): boolean { return context.currentTokenParent.kind === SyntaxKind.VariableDeclarationList && context.currentTokenParent.getStart(context.sourceFile) === context.currentTokenSpan.pos; diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index 609f08f3a7696..5db938d63bd36 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -237,9 +237,9 @@ export function delint(sourceFile: ts.SourceFile) { >sourceFile : ts.SourceFile >getLineAndCharacterOfPosition : (pos: number) => ts.LineAndCharacter >node.getStart() : number ->node.getStart : (sourceFile?: ts.SourceFile) => number +>node.getStart : (sourceFile?: ts.SourceFile, skipDecorators?: boolean) => number >node : ts.Node ->getStart : (sourceFile?: ts.SourceFile) => number +>getStart : (sourceFile?: ts.SourceFile, skipDecorators?: boolean) => number console.log(`${sourceFile.fileName} (${line + 1},${character + 1}): ${message}`); >console.log(`${sourceFile.fileName} (${line + 1},${character + 1}): ${message}`) : any From 609036a2d669572145fb18d96a213fa3f5c6e784 Mon Sep 17 00:00:00 2001 From: Ron Buckton Date: Wed, 8 Apr 2015 17:06:00 -0700 Subject: [PATCH 3/3] PR feedback and baseline updates --- src/compiler/utilities.ts | 14 ++++++++------ src/services/formatting/formatting.ts | 4 ++-- src/services/formatting/rules.ts | 14 +++----------- src/services/services.ts | 6 +++--- tests/baselines/reference/APISample_linter.types | 4 ++-- tests/cases/fourslash/formattingDecorators.ts | 14 +++++++------- 6 files changed, 25 insertions(+), 31 deletions(-) diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 30f392e5ded2a..a10be6ba22595 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -150,20 +150,22 @@ module ts { return !nodeIsMissing(node); } - export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile, skipDecorators?: boolean): number { + export function getTokenPosOfNode(node: Node, sourceFile?: SourceFile): 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; } - let pos = node.pos; - if (skipDecorators && node.decorators) { - // Skip past decorators - pos = node.decorators.end; + return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.pos); + } + + export function getNonDecoratorTokenPosOfNode(node: Node, sourceFile?: SourceFile): number { + if (nodeIsMissing(node) || !node.decorators) { + return getTokenPosOfNode(node, sourceFile); } - return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, pos); + return skipTrivia((sourceFile || getSourceFileOfNode(node)).text, node.decorators.end); } export function getSourceTextOfNodeFromSourceFile(sourceFile: SourceFile, node: Node): string { diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index ddf2f4cad27b7..0f5f49f3d8fb4 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -330,7 +330,7 @@ module ts.formatting { let startLine = sourceFile.getLineAndCharacterOfPosition(enclosingNode.getStart(sourceFile)).line; let undecoratedStartLine = startLine; if (enclosingNode.decorators) { - undecoratedStartLine = sourceFile.getLineAndCharacterOfPosition(enclosingNode.getStart(sourceFile, /*skipDecorators*/ true)).line; + undecoratedStartLine = sourceFile.getLineAndCharacterOfPosition(getNonDecoratorTokenPosOfNode(enclosingNode, sourceFile)).line; } let delta = getOwnOrInheritedDelta(enclosingNode, options, sourceFile); @@ -561,7 +561,7 @@ module ts.formatting { let undecoratedChildStartLine = childStartLine; if (child.decorators) { - undecoratedChildStartLine = sourceFile.getLineAndCharacterOfPosition(child.getStart(sourceFile, /*skipDecorators*/ true)).line; + undecoratedChildStartLine = sourceFile.getLineAndCharacterOfPosition(getNonDecoratorTokenPosOfNode(child, sourceFile)).line; } // if child is a list item - try to get its indentation diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index ac3d7fe678307..f5cb8cb4e6487 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -670,18 +670,10 @@ module ts.formatting { } static NodeIsInDecoratorContext(node: Node): boolean { - if (node.parserContextFlags & ParserContextFlags.Decorator) { - return true; + while (isExpression(node)) { + node = node.parent; } - while (node) { - if (isExpression(node)) { - node = node.parent; - } - else { - return node.kind === SyntaxKind.Decorator; - } - } - return false; + return node.kind === SyntaxKind.Decorator; } static IsStartOfVariableDeclarationList(context: FormattingContext): boolean { diff --git a/src/services/services.ts b/src/services/services.ts index 042e2f4f01e1e..86c323f24bfbe 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -19,7 +19,7 @@ module ts { getChildCount(sourceFile?: SourceFile): number; getChildAt(index: number, sourceFile?: SourceFile): Node; getChildren(sourceFile?: SourceFile): Node[]; - getStart(sourceFile?: SourceFile, skipDecorators?: boolean): number; + getStart(sourceFile?: SourceFile): number; getFullStart(): number; getEnd(): number; getWidth(sourceFile?: SourceFile): number; @@ -149,8 +149,8 @@ module ts { return getSourceFileOfNode(this); } - public getStart(sourceFile?: SourceFile, skipDecorators?: boolean): number { - return getTokenPosOfNode(this, sourceFile, skipDecorators); + public getStart(sourceFile?: SourceFile): number { + return getTokenPosOfNode(this, sourceFile); } public getFullStart(): number { diff --git a/tests/baselines/reference/APISample_linter.types b/tests/baselines/reference/APISample_linter.types index 5db938d63bd36..609f08f3a7696 100644 --- a/tests/baselines/reference/APISample_linter.types +++ b/tests/baselines/reference/APISample_linter.types @@ -237,9 +237,9 @@ export function delint(sourceFile: ts.SourceFile) { >sourceFile : ts.SourceFile >getLineAndCharacterOfPosition : (pos: number) => ts.LineAndCharacter >node.getStart() : number ->node.getStart : (sourceFile?: ts.SourceFile, skipDecorators?: boolean) => number +>node.getStart : (sourceFile?: ts.SourceFile) => number >node : ts.Node ->getStart : (sourceFile?: ts.SourceFile, skipDecorators?: boolean) => number +>getStart : (sourceFile?: ts.SourceFile) => number console.log(`${sourceFile.fileName} (${line + 1},${character + 1}): ${message}`); >console.log(`${sourceFile.fileName} (${line + 1},${character + 1}): ${message}`) : any diff --git a/tests/cases/fourslash/formattingDecorators.ts b/tests/cases/fourslash/formattingDecorators.ts index 9fc63d9d47bb6..366b9cb7729bc 100644 --- a/tests/cases/fourslash/formattingDecorators.ts +++ b/tests/cases/fourslash/formattingDecorators.ts @@ -1,11 +1,11 @@ /// -/////*1*/ @ decorator1 +/////*1*/ @ decorator1 /////*2*/ @ decorator2 /////*3*/ @decorator3 /////*4*/ @ decorator4 @ decorator5 /////*5*/class C { -/////*6*/ @ decorator6 +/////*6*/ @ decorator6 /////*7*/ @ decorator7 /////*8*/ @decorator8 /////*9*/ method1() { } @@ -13,7 +13,7 @@ /////*10*/ @ decorator9 @ decorator10 @decorator11 method2() { } //// //// method3( -/////*11*/ @ decorator12 +/////*11*/ @ decorator12 /////*12*/ @ decorator13 /////*13*/ @decorator14 /////*14*/ x) { } @@ -21,21 +21,21 @@ //// method4( /////*15*/ @ decorator15 @ decorator16 @decorator17 x) { } //// -/////*16*/ @ decorator18 +/////*16*/ @ decorator18 /////*17*/ @ decorator19 -/////*18*/ @decorator20 +/////*18*/ @decorator20 /////*19*/ ["computed1"]() { } //// /////*20*/ @ decorator21 @ decorator22 @decorator23 ["computed2"]() { } //// -/////*21*/ @ decorator24 +/////*21*/ @ decorator24 /////*22*/ @ decorator25 /////*23*/ @decorator26 /////*24*/ get accessor1() { } //// /////*25*/ @ decorator27 @ decorator28 @decorator29 get accessor2() { } //// -/////*26*/ @ decorator30 +/////*26*/ @ decorator30 /////*27*/ @ decorator31 /////*28*/ @decorator32 /////*29*/ property1;