Repository: prettier/prettier (JavaScript)
Date: 2018-07-10 19:16:43+00:00
Task type: Feature

Issue:
inline decorators
continue from #325, I think it need more discussion

It's really ugly to put them in one line in field definition like in TypeORM.

maybe only decorators without () should be inline?

before

```typescript
@Entity()
export class Board {
  
    @PrimaryGeneratedColumn()
    id: number;
    
    @Column()
    slug: string;
    
    @Column()
    name: string;
    
    @Column()
    theme: string;
    
    @Column()
    description: string;
    
    @OneToMany(type => Topic, topic => topic.board)
    topics: Topic[]
  
}
```

after

```typescript
@Entity()
export class Board {
  @PrimaryGeneratedColumn() id: number;

  @Column() slug: string;

  @Column() name: string;

  @Column() theme: string;

  @Column() description: string;

  @OneToMany(type => Topic, topic => topic.board)
  topics: Topic[];
}
```


Issue discussion:
This was fixed way back in #1910

**Prettier 1.7.4**
[Playground link](https://prettier.io/playground/#%7B%22content%22%3A%22%40Entity()%5Cnexport%20class%20Board%20%7B%5Cn%20%20%5Cn%20%20%20%20%40PrimaryGeneratedColumn()%5Cn%20%20%20%20id%3A%20number%3B%5Cn%20%20%20%20%5Cn%20%20%20%20%40Column()%5Cn%20%20%20%20slug%3A%20string%3B%5Cn%20%20%20%20%5Cn%20%20%20%20%40Column()%5Cn%20%20%20%20name%3A%20string%3B%5Cn%20%20%20%20%5Cn%20%20%20%20%40Column()%5Cn%20%20%20%20theme%3A%20string%3B%5Cn%20%20%20%20%5Cn%20%20%20%20%40Column()%5Cn%20%20%20%20description%3A%20string%3B%5Cn%20%20%20%20%5Cn%20%20%20%20%40OneToMany(type%20%3D%3E%20Topic%2C%20topic%20%3D%3E%20topic.board)%5Cn%20%20%20%20topics%3A%20Topic%5B%5D%5Cn%20%20%5Cn%7D%22%2C%22options%22%3A%7B%22ast%22%3Afalse%2C%22bracketSpacing%22%3Atrue%2C%22doc%22%3Afalse%2C%22jsxBracketSameLine%22%3Afalse%2C%22output2%22%3Afalse%2C%22parser%22%3A%22typescript%22%2C%22printWidth%22%3A80%2C%22semi%22%3Atrue%2C%22singleQuote%22%3Afalse%2C%22tabWidth%22%3A2%2C%22trailingComma%22%3A%22none%22%2C%22useTabs%22%3Afalse%7D%7D)
```sh
--parser typescript
```

**Input:**
```tsx
@Entity()
export class Board {
  
    @PrimaryGeneratedColumn()
    id: number;
    
    @Column()
    slug: string;
    
    @Column()
    name: string;
    
    @Column()
    theme: string;
    
    @Column()
    description: string;
    
    @OneToMany(type => Topic, topic => topic.board)
    topics: Topic[]
  
}
```

**Output:**
```tsx
@Entity()
export class Board {
  @PrimaryGeneratedColumn() id: number;

  @Column() slug: string;

  @Column() name: string;

  @Column() theme: string;

  @Column() description: string;

  @OneToMany(type => Topic, topic => topic.board)
  topics: Topic[];
}

```
@azz the output is very undesirable for some of us. very hard to see the actual properties when decorators are inlined...
Agreed. Who likes inlined decorators? =/
@azz can this please be re-opened? Inline decorators are ugly. I can gather lot of people who will tell the same. Also as you can see lot of people in merged PR were complaining about inline decorators.
Can this styling choice be reevaluated?
Can one of you open a new issue with **real world code examples** that show how this style looks worse?
A TypeORM entity with inline decorators as prettier format it
![image](https://user-images.githubusercontent.com/412489/40514798-edd67006-5f80-11e8-9d95-6876db053c08.png)

The same TypeORM entity with decorators in its own line
![image](https://user-images.githubusercontent.com/412489/40514914-40c54008-5f81-11e8-9a06-fff069933af8.png)

If the decorator has parameters then it is in its own line. But if doesn't have parameters it is inlined next to the property. This makes it really hard to spot which are the properties at first sight. And honestly, if you tell me you prefer the first one but there are a lot of us who prefer the second one, then that should be enough reason to make it configurable IMHO.
Just stumbled upon this same issue when working with TypeORM entities. Please reconsider this - the inlined example above is very hard to parse at a glance.
should we re-open this issue  ?

@azz 
Decorators still aren't part of the language, so I'm not in any hurry to create churn when the spec may change (it actually already has). If we do change it we'll likely get a flood of feedback from people who like it the way it is.

The current behaviour was requested in #1898. 
@azz how is the decision process? what about making it configurable as suggested in the discussion you mentioned?
Have a read of our [option philosophy](https://prettier.io/docs/en/option-philosophy.html).
> Decorators still aren't part of the language, so I'm not in any hurry to create churn when the spec may change (it actually already has). If we do change it we'll likely get a flood of feedback from people who like it the way it is.

First, even decorators are not "part of the language", they are part of the TypeScript which is completely supported by prettier. So, we can say that it is part of the language.

Second, if even decorators will change they semantically will stay same, otherwise they won't be called decorators anymore.

Third and the most important, if you are not sure how to format this functionality then its better not format it at all. 

What I want to say is that if you are not sure how to properly format this code because its not part of the language then its probably better not to format it at all and let people decide how to format it. I see that some guy decided to format it the way he liked, sent PR and you accepted it, but... its not how it should be done. Prettier is very popular nowadays and this popularity brings big responsibility to it, and each such PR should be taken carefully with enough level of insurance that this change bring a better code and most people going to admit and accept it.

I know, its hard to achieve, because people starting being active only when they get issues, and maybe this is exact case.

I haven't spread a word about this issue in the community, but I already see that my comment above received 20 votes which may be enough to make you think that something is being formatted not the way people actually prefer. Please re-consider PR you accepted that already has more downvotes than upvotes.
> even decorators are not "part of the language", they are part of the TypeScript 

To the same extent as they are a part of JavaScript. Decorators are behind the `experimentalDecorators` flag in TypeScript. 

> if you are not sure how to format this functionality then its better not format it at all.

This would undermine the value prospect of Prettier. We've had requests to ignore the input code 100% (#2068). We have the `// prettier-ignore` comment as an escape hatch which will allows you to opt-out of formatting a block of code, but we try to ignore the source text as much as possible to reduce ambiguity and confusion. 

> some guy decided to format it the way he liked, sent PR and you accepted it

That "some guy" is @vjeux (#1910) and he is the number one contributor to Prettier. 😄 

> my comment above received 20 votes

Just to put it in perspective, we've got issues that we haven't acted on with 100+ votes (e.g. #3847). We walk a very fine line when making changes as it effects a very large amount of people, and generally the people who like the current behaviour don't go and search for issues to change it. 

I want to clarify my previous comment and say that I actually don't have an opinion on this issue as I've avoided decorators for the most part. _If_ the community at-large was in favour of the change then it would make sense to proceed. However, we need to gather more data and more feedback before making such a change.
> However, we need to gather more data and more feedback before making such a change.

why you did not gather data before implementing current behaviour? All I see is in issues just one-two opinions and issues are even marked as "subjective". I think if you are not sure about some formatting, then its really better not to do it.

> Just to put it in perspective, we've got issues that we haven't acted on with 100+ votes

now count. You have 100 votes for a popular use case. And you have a 25 votes for non-popular, experimental syntax, used only by some people. Don't you think think that value here is already higher then in that 100+ votes issue?

> We walk a very fine line when making changes as it effects a very large amount of people,

exactly! That's why we are worrying here. Current formatting effects us and we don't understand why current changes ware made without walking a very fine line.
> That's why we are worrying here. Current formatting effects us and we don't understand why current changes ware made without walking a very fine line.

The change you're referring to happened a year ago. `1.4.0` had TS support, `1.4.1` had this change, both were released on the same day. So it wasn't really a _change_ in that sense, more-so it was early tuning. 
We use TypeScript in most of our projects and we indeed use decorators a lot. We have now decided to ditch Prettier and go back to our previous formatter because of this. 

If in the future this gets addressed by either making it configurable or by don't formatting decorators at all, someone please let me know. Thanks.

This is another big one for us.  Inlined decorators are absolutely horrible IMO.  Source code reading has been hurt by 78.567% by this ;-)


so pick one of them would solve problem

1. all decorators should not inline
2. decorators with bracket should not inline
To make TypeORM better, let's detect classes decorated with `@Entity()` and not inline any of their decorators.
TypeORM is just one example of this. Our case is in Angular which has a heap of different decorators. If there is going to be a change to make this configurable / optional please don't just do it for one specific case.
yeah, it should not be specific for some library, problem exist not because of library
@paulparton @pleerock Can you share real world examples of code with before/after that were affected by Prettier?

The only examples in this thread so far are about TypeORM.

It’s very hard to come up with ideas without seeing actual code
@duailibe its not related to any specific library like TypeORM, so treat examples as generic since they only use decorators, not typeorm or other-library specific functionality/feature/style or anything else. Just decorators. Just take a look on a original post and compare "before" and "after". Most of people admin that before is better. Plus try to add more decorators on properties, try to add more decorators with longer names, no matter if its from some library or you own created decorators - the result is ugly and less readable if they were each in a separate row.
@pleerock @paulparton I have no personal issue changing it but I want to fully understand the issue before making a change, since prettier is used by so many people, and it's hard to do that without code examples.
Looks like #325 also mentions mobx:

**Prettier 1.13.4**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEBLAtgBwgJxgAmHwgCMBnOHANwEMSAbOfAX3wDMcJ18AdEdUgA8+Abh5RxYejTJl8AeRwATSgBlUUJsHH58AAVIVqdRjvyYcqMHCT4oAV3QlK+ALz4ADGIlRdB8pS0DHBmNAL2sLYOTi7uAIzeZpBQZDA49mAwuAAUFlZwAJSEZrowABaoZAB0edZu5pbW3rrM4mZ6kFj28EpmAOZwBFkwNPTZRUQl+DiD9ji+5ZU1jUwAVPiL1WEQETDNLOKtUCAANCAQmDCo0GTIoDQ4nADuAAoPCLcoNFQQqEqnIBIOBoYAA1oMAMqYEEaPrINL2OBnDRGGAvYF9dA0ZBsUYUM4AKzIggAQsCwZCwnB1JocXikSBoTgjMhAXQAJ70aAAvKwADqf3KyAAHB4zhYIBQ+cDMKyLHAjFQ4ACZgBHeyoGbomiY7FIXH0fEgCjoVDw9IMsiwxgARXsEHgdMNDJGJAFSiFSAATGc0jRUPRYQBhLhY1lQaDKs72CgAFTonwNFGYzCAA)
```sh
--parser babylon
```

**Input:**
```jsx
import { observable } from "mobx";

class OrderLine {
  @observable
  price: number = 0;

  @observable
  amount: number = 1;

  constructor(price) {
    this.price = price;
  }

  @computed
  get total() { 
    return this.price * this.amount;
  }
}

```

**Output:**
```jsx
import { observable } from "mobx";

class OrderLine {
  @observable price: number = 0;

  @observable amount: number = 1;

  constructor(price) {
    this.price = price;
  }

  @computed
  get total() {
    return this.price * this.amount;
  }
}

```
@duailibe @suchipi Heya! sure thing, here is some Angular code.

Input

<img width="714" alt="screen shot 2018-06-29 at 8 48 18 am" src="https://user-images.githubusercontent.com/5544897/42119762-006f68f0-7c53-11e8-81b0-a4402ce1e2aa.png">

Output

<img width="698" alt="screen shot 2018-06-29 at 8 53 07 am" src="https://user-images.githubusercontent.com/5544897/42119768-0b368cf0-7c53-11e8-9801-772974ec3690.png">

> why you did not gather data before implementing current behaviour? All I see is in issues just one-two opinions and issues are even marked as "subjective". I think if you are not sure about some formatting, then its really better not to do it.

I think this should be a part of prettier philosophy: implement a formatter only after gathering data.
Established similar structures from other programming languages:

c# Attributes

![attributescsharp](https://user-images.githubusercontent.com/185294/42186882-7904c434-7e4e-11e8-83ee-c12322dfb182.jpg)

In Visual Studio and also with all online formatters in existence, they will be on separate lines.

java annotations:

![javaannotations](https://user-images.githubusercontent.com/185294/42186959-be8b104e-7e4e-11e8-96b4-da96580dbdae.png)
[Google style guide for them](https://google.github.io/styleguide/javaguide.html#s4.8.5-annotations)
also [OpenJDK](http://cr.openjdk.java.net/~alundblad/styleguide/index-v6.html#toc-annotations)
also [Kotlin](https://kotlinlang.org/docs/reference/coding-conventions.html), which says:

> Annotations are typically placed on separate lines, before the declaration to which they are attached, and with the same indentation

Rust attributes are also always on their own line, in all the examples I've seen. [Here's a style guide](https://github.com/rust-lang-nursery/fmt-rfcs/blob/master/guide/guide.md#attributes). [There are even PHP preprocessors which add annotations, and they also put them on new lines](https://github.com/mzabriskie/annotate.php).
I'm convinced- let's change it
There's also the decorators proposal itself: https://github.com/tc39/proposal-decorators

There, they are also on their own lines.

Is this officially planned to be reverted? If yes, when?
> Is this officially planned to be reverted? If yes, when?

We don’t really have an official roadmap. It’ll happen when someone (a maintainer or an external contributor) opens a PR :)

Solution patch:
diff --git a/src/common/util.js b/src/common/util.js
index fece29049946..ab5e05044c2f 100644
--- a/src/common/util.js
+++ b/src/common/util.js
@@ -786,6 +786,22 @@ function addTrailingComment(node, comment) {
   addCommentHelper(node, comment);
 }
 
+function isWithinParentArrayProperty(path, propertyName) {
+  const node = path.getValue();
+  const parent = path.getParentNode();
+
+  if (parent == null) {
+    return false;
+  }
+
+  if (!Array.isArray(parent[propertyName])) {
+    return false;
+  }
+
+  const key = path.getName();
+  return parent[propertyName][key] === node;
+}
+
 module.exports = {
   punctuationRegex,
   punctuationCharRange,
@@ -823,5 +839,6 @@ module.exports = {
   matchAncestorTypes,
   addLeadingComment,
   addDanglingComment,
-  addTrailingComment
+  addTrailingComment,
+  isWithinParentArrayProperty
 };
diff --git a/src/language-js/printer-estree.js b/src/language-js/printer-estree.js
index bed172c6ad1b..672851499d64 100644
--- a/src/language-js/printer-estree.js
+++ b/src/language-js/printer-estree.js
@@ -20,7 +20,8 @@ const {
   getPenultimate,
   startsWithNoLookaheadToken,
   getIndentSize,
-  matchAncestorTypes
+  matchAncestorTypes,
+  isWithinParentArrayProperty
 } = require("../common/util");
 const {
   isNextLineEmpty,
@@ -94,7 +95,12 @@ function genericPrint(path, options, printPath, args) {
     // responsible for printing node.decorators.
     !getParentExportDeclaration(path)
   ) {
-    let separator = hardline;
+    const separator =
+      node.decorators.length === 1 &&
+      isWithinParentArrayProperty(path, "params")
+        ? line
+        : hardline;
+
     path.each(decoratorPath => {
       let decorator = decoratorPath.getValue();
       if (decorator.expression) {
@@ -103,27 +109,6 @@ function genericPrint(path, options, printPath, args) {
         decorator = decorator.callee;
       }
 
-      if (
-        node.decorators.length === 1 &&
-        node.type !== "ClassDeclaration" &&
-        node.type !== "MethodDefinition" &&
-        node.type !== "ClassMethod" &&
-        (decorator.type === "Identifier" ||
-          decorator.type === "MemberExpression" ||
-          decorator.type === "OptionalMemberExpression" ||
-          ((decorator.type === "CallExpression" ||
-            decorator.type === "OptionalCallExpression") &&
-            (decorator.arguments.length === 0 ||
-              (decorator.arguments.length === 1 &&
-                (isStringLiteral(decorator.arguments[0]) ||
-                  decorator.arguments[0].type === "Identifier" ||
-                  decorator.arguments[0].type === "MemberExpression" ||
-                  decorator.arguments[0].type ===
-                    "OptionalMemberExpression")))))
-      ) {
-        separator = line;
-      }
-
       decorators.push(printPath(decoratorPath), separator);
     }, "decorators");
   } else if (


Test patch:
diff --git a/tests/decorators-ts/__snapshots__/jsfmt.spec.js.snap b/tests/decorators-ts/__snapshots__/jsfmt.spec.js.snap
new file mode 100644
index 000000000000..6db27015db0f
--- /dev/null
+++ b/tests/decorators-ts/__snapshots__/jsfmt.spec.js.snap
@@ -0,0 +1,223 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`accessor-decorator.ts - typescript-verify 1`] = `
+class Point {
+  private _x: number;
+  private _y: number;
+  constructor(x: number, y: number) {
+    this._x = x;
+    this._y = y;
+  }
+
+  @configurable(false)
+  get x() {
+    return this._x;
+  }
+
+  @configurable(false)
+  get y() {
+    return this._y;
+  }
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class Point {
+  private _x: number;
+  private _y: number;
+  constructor(x: number, y: number) {
+    this._x = x;
+    this._y = y;
+  }
+
+  @configurable(false)
+  get x() {
+    return this._x;
+  }
+
+  @configurable(false)
+  get y() {
+    return this._y;
+  }
+}
+
+`;
+
+exports[`class-decorator.ts - typescript-verify 1`] = `
+@sealed
+class Greeter {
+  greeting: string;
+  constructor(message: string) {
+    this.greeting = message;
+  }
+  greet() {
+    return "Hello, " + this.greeting;
+  }
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+@sealed
+class Greeter {
+  greeting: string;
+  constructor(message: string) {
+    this.greeting = message;
+  }
+  greet() {
+    return "Hello, " + this.greeting;
+  }
+}
+
+`;
+
+exports[`method-decorator.ts - typescript-verify 1`] = `
+class Greeter {
+  greeting: string;
+  constructor(message: string) {
+    this.greeting = message;
+  }
+
+  @enumerable(false)
+  greet() {
+    return "Hello, " + this.greeting;
+  }
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class Greeter {
+  greeting: string;
+  constructor(message: string) {
+    this.greeting = message;
+  }
+
+  @enumerable(false)
+  greet() {
+    return "Hello, " + this.greeting;
+  }
+}
+
+`;
+
+exports[`multiple.ts - typescript-verify 1`] = `
+class C {
+  @f()
+  @g()
+  method() {}
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class C {
+  @f()
+  @g()
+  method() {}
+}
+
+`;
+
+exports[`parameter-decorator.ts - typescript-verify 1`] = `
+class Greeter {
+  greeting: string;
+
+  constructor(message: string) {
+    this.greeting = message;
+  }
+
+  @validate
+  greet(@required name: string) {
+    return "Hello " + name + ", " + this.greeting;
+  }
+
+  @validate
+  destructured(@required { toString }: Object) {
+    return Function.prototype.toString.apply(toString);
+  }
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class Greeter {
+  greeting: string;
+
+  constructor(message: string) {
+    this.greeting = message;
+  }
+
+  @validate
+  greet(@required name: string) {
+    return "Hello " + name + ", " + this.greeting;
+  }
+
+  @validate
+  destructured(@required { toString }: Object) {
+    return Function.prototype.toString.apply(toString);
+  }
+}
+
+`;
+
+exports[`property-decorator.ts - typescript-verify 1`] = `
+class Greeter {
+  @format("Hello, %s") greeting: string;
+
+  constructor(message: string) {
+    this.greeting = message;
+  }
+  greet() {
+    let formatString = getFormat(this, "greeting");
+    return formatString.replace("%s", this.greeting);
+  }
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+class Greeter {
+  @format("Hello, %s")
+  greeting: string;
+
+  constructor(message: string) {
+    this.greeting = message;
+  }
+  greet() {
+    let formatString = getFormat(this, "greeting");
+    return formatString.replace("%s", this.greeting);
+  }
+}
+
+`;
+
+exports[`typeorm.ts - typescript-verify 1`] = `
+@Entity()
+export class Board {
+
+    @PrimaryGeneratedColumn()
+    id: number;
+
+    @Column()
+    slug: string;
+
+    @Column()
+    name: string;
+
+    @Column()
+    theme: string;
+
+    @Column()
+    description: string;
+
+    @OneToMany(type => Topic, topic => topic.board)
+    topics: Topic[]
+
+}
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+@Entity()
+export class Board {
+  @PrimaryGeneratedColumn()
+  id: number;
+
+  @Column()
+  slug: string;
+
+  @Column()
+  name: string;
+
+  @Column()
+  theme: string;
+
+  @Column()
+  description: string;
+
+  @OneToMany(type => Topic, topic => topic.board)
+  topics: Topic[];
+}
+
+`;
diff --git a/tests/decorators-ts/accessor-decorator.ts b/tests/decorators-ts/accessor-decorator.ts
new file mode 100644
index 000000000000..a31231328cd4
--- /dev/null
+++ b/tests/decorators-ts/accessor-decorator.ts
@@ -0,0 +1,18 @@
+class Point {
+  private _x: number;
+  private _y: number;
+  constructor(x: number, y: number) {
+    this._x = x;
+    this._y = y;
+  }
+
+  @configurable(false)
+  get x() {
+    return this._x;
+  }
+
+  @configurable(false)
+  get y() {
+    return this._y;
+  }
+}
diff --git a/tests/decorators-ts/class-decorator.ts b/tests/decorators-ts/class-decorator.ts
new file mode 100644
index 000000000000..5a0586e243f3
--- /dev/null
+++ b/tests/decorators-ts/class-decorator.ts
@@ -0,0 +1,10 @@
+@sealed
+class Greeter {
+  greeting: string;
+  constructor(message: string) {
+    this.greeting = message;
+  }
+  greet() {
+    return "Hello, " + this.greeting;
+  }
+}
diff --git a/tests/decorators-ts/jsfmt.spec.js b/tests/decorators-ts/jsfmt.spec.js
new file mode 100644
index 000000000000..2ea3bb6eb2e4
--- /dev/null
+++ b/tests/decorators-ts/jsfmt.spec.js
@@ -0,0 +1,1 @@
+run_spec(__dirname, ["typescript"]);
diff --git a/tests/decorators-ts/method-decorator.ts b/tests/decorators-ts/method-decorator.ts
new file mode 100644
index 000000000000..3ec4f14a9729
--- /dev/null
+++ b/tests/decorators-ts/method-decorator.ts
@@ -0,0 +1,11 @@
+class Greeter {
+  greeting: string;
+  constructor(message: string) {
+    this.greeting = message;
+  }
+
+  @enumerable(false)
+  greet() {
+    return "Hello, " + this.greeting;
+  }
+}
diff --git a/tests/decorators-ts/multiple.ts b/tests/decorators-ts/multiple.ts
new file mode 100644
index 000000000000..9b453550f5db
--- /dev/null
+++ b/tests/decorators-ts/multiple.ts
@@ -0,0 +1,5 @@
+class C {
+  @f()
+  @g()
+  method() {}
+}
diff --git a/tests/decorators-ts/parameter-decorator.ts b/tests/decorators-ts/parameter-decorator.ts
new file mode 100644
index 000000000000..69cbd7f1e5eb
--- /dev/null
+++ b/tests/decorators-ts/parameter-decorator.ts
@@ -0,0 +1,17 @@
+class Greeter {
+  greeting: string;
+
+  constructor(message: string) {
+    this.greeting = message;
+  }
+
+  @validate
+  greet(@required name: string) {
+    return "Hello " + name + ", " + this.greeting;
+  }
+
+  @validate
+  destructured(@required { toString }: Object) {
+    return Function.prototype.toString.apply(toString);
+  }
+}
diff --git a/tests/decorators-ts/property-decorator.ts b/tests/decorators-ts/property-decorator.ts
new file mode 100644
index 000000000000..a55cfc288ca9
--- /dev/null
+++ b/tests/decorators-ts/property-decorator.ts
@@ -0,0 +1,11 @@
+class Greeter {
+  @format("Hello, %s") greeting: string;
+
+  constructor(message: string) {
+    this.greeting = message;
+  }
+  greet() {
+    let formatString = getFormat(this, "greeting");
+    return formatString.replace("%s", this.greeting);
+  }
+}
diff --git a/tests/decorators-ts/typeorm.ts b/tests/decorators-ts/typeorm.ts
new file mode 100644
index 000000000000..561defa869ef
--- /dev/null
+++ b/tests/decorators-ts/typeorm.ts
@@ -0,0 +1,22 @@
+@Entity()
+export class Board {
+
+    @PrimaryGeneratedColumn()
+    id: number;
+
+    @Column()
+    slug: string;
+
+    @Column()
+    name: string;
+
+    @Column()
+    theme: string;
+
+    @Column()
+    description: string;
+
+    @OneToMany(type => Topic, topic => topic.board)
+    topics: Topic[]
+
+}
diff --git a/tests/decorators/__snapshots__/jsfmt.spec.js.snap b/tests/decorators/__snapshots__/jsfmt.spec.js.snap
index c3ee92f2dd0d..24fa574b0d2b 100644
--- a/tests/decorators/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/decorators/__snapshots__/jsfmt.spec.js.snap
@@ -108,8 +108,10 @@ import { observable } from "mobx";
 
 @observer
 class OrderLine {
-  @observable price: number = 0;
-  @observable amount: number = 1;
+  @observable
+  price: number = 0;
+  @observable
+  amount: number = 1;
 
   constructor(price) {
     this.price = price;
diff --git a/tests/typescript/conformance/types/decorator/__snapshots__/jsfmt.spec.js.snap b/tests/typescript/conformance/types/decorator/__snapshots__/jsfmt.spec.js.snap
index 71b1bc3e6e4b..d16da936bd6e 100644
--- a/tests/typescript/conformance/types/decorator/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/typescript/conformance/types/decorator/__snapshots__/jsfmt.spec.js.snap
@@ -8,6 +8,7 @@ enum E {}
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 declare function dec<T>(target: T): T;
 
-@dec enum E {}
+@dec
+enum E {}
 
 `;
diff --git a/tests/typescript_decorators/__snapshots__/jsfmt.spec.js.snap b/tests/typescript_decorators/__snapshots__/jsfmt.spec.js.snap
index db62fff8f83a..ed10bea50a70 100644
--- a/tests/typescript_decorators/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/typescript_decorators/__snapshots__/jsfmt.spec.js.snap
@@ -49,7 +49,8 @@ export class TabCompletionController {}
   selector: "angular-component"
 })
 class AngularComponent {
-  @Input() myInput: string;
+  @Input()
+  myInput: string;
 }
 
 `;
@@ -217,10 +218,14 @@ class Class2 {
 }
 
 class Class3 {
-  @d1 fieldA;
-  @d2(foo) fieldB;
-  @d3.bar fieldC;
-  @d4.baz() fieldD;
+  @d1
+  fieldA;
+  @d2(foo)
+  fieldB;
+  @d3.bar
+  fieldC;
+  @d4.baz()
+  fieldD;
 
   constructor(
     @d1 private x: number,