Repository: ember-cli/ember-cli
Pull request #7450 (2017-11-20 14:13:05)

Add prettier and eslint-plugin-ember to linting config.
Hot on the heels of updating the linting configuration to use a single file, this adds `prettier` and `eslint-plugin-ember` to a new app out of the box.

`eslint-plugin-ember@5` will be released soon, and includes a number of changes to the default recommended config. Specifically, the recommended set follows with `eslint`'s own strategy of only including "saftey related" rules in the recommended rule set. As such, all "style related" rules are no longer "on by default".  This definitely does not infer there is anything _wrong_ with those rules (and we may even add some of them into the default app config in the future), but we would like to bring `eslint-plugin-ember` into ember-cli gradually.

`prettier` has taken the JavaScript ecosystem by storm! It has quickly become the most common way to acheive "standard code style" without being nit-picky with linting rules. The configuration that is landed here integrates `prettier` into `eslint` so that `eslint` properly identifies things that are not "pretty" and a quick `eslint --fix` will auto-correct them. This also means that any editors with built-in `eslint --fix` support already support `prettier`. 🎉

alexlafroscia: A few thoughts: 

1. Prettier and Ember together make a ton of sense. Doubling down on community convention feels very “Ember” to me
2. Might want to think about updating the ESLint config in the `tests` directory that is generated by default. I’ve has issues with it not being marked as `root: true` when using the fixer on test files. The solve was to mark it as root and then explicitly extend from the config in the parent directory. 
3. Does it feel contradictory to turn off style-related things in the recommended config and then turn on Prettier, which is purely style-related? I love making it easier to get started with Prettier but am unsure about aggressively making decisions about code style for the community
rwjblue: > Prettier and Ember together make a ton of sense. Doubling down on community convention feels very “Ember” to me

😄 🐹 ❤️ 

> Might want to think about updating the ESLint config in the tests directory that is generated by default. I’ve has issues with it not being marked as root: true when using the fixer on test files. The solve was to mark it as root and then explicitly extend from the config in the parent directory.

As of https://github.com/ember-cli/ember-cli/pull/7443 we only have a single eslint config (leveraging the newish `overrides` + globs), which should completely remove this issue. I also tested using both `neovim` + `ALE` (configured to run `eslint` as a fixer) and `emacs` + `flycheck`, before the changes in https://github.com/ember-cli/ember-cli/pull/7443 I had the same issue you mention here, after those changes things work well without modification.

> Does it feel contradictory to turn off style-related things in the recommended config and then turn on Prettier, which is purely style-related? I love making it easier to get started with Prettier but am unsure about aggressively making decisions about code style for the community

Thanks for bringing this up! I totally understand this position (and somewhat agree), however I still believe that the PR as it stands today is a good path forward. The primary difference here is the ability to `auto-fix`. With the `prettier` configuration that is added in this PR the rules do not seem "nit-picky" (even though they **totally are**), this is because a simple `eslint --fix` is all that is needed to clean things up. It essentially allows me to write JS how I "want" to (and TBH, I'm a tad sloppy 😉) and not worry about the exact formatting while editing.  This is _extremely_ empowering IMHO.

IMHO, the generally agreed upon stylistic rules (like `order-in-*`) in `eslint-plugin-ember` are *awesome*! However, to enable by default I think we will need more robust fixer support (this is being worked on in https://github.com/ember-cli/eslint-plugin-ember/pull/172).
kratiahuja: Nvm I can see that is done using eslint —fix 
Turbo87: yep, although we could consider adding a `lint` (and/or `lint:fix`) script to `package.json` to make it easier to invoke ESLint. but that seems like a topic for a separate PR.

Patch:
diff --git a/blueprints/addon/files/addon-config/ember-try.js b/blueprints/addon/files/addon-config/ember-try.js
index 1ab8ae562..0a6fdce51 100644
--- a/blueprints/addon/files/addon-config/ember-try.js
+++ b/blueprints/addon/files/addon-config/ember-try.js
@@ -5,71 +5,71 @@ module.exports = {
       name: 'ember-lts-2.12',
       npm: {
         devDependencies: {
-          'ember-source': '~2.12.0'
-        }
-      }
+          'ember-source': '~2.12.0',
+        },
+      },
     },
     {
       name: 'ember-lts-2.16',
       npm: {
         devDependencies: {
-          'ember-source': '~2.16.0'
-        }
-      }
+          'ember-source': '~2.16.0',
+        },
+      },
     },
     {
       name: 'ember-release',
       bower: {
         dependencies: {
-          'ember': 'components/ember#release'
+          ember: 'components/ember#release',
         },
         resolutions: {
-          'ember': 'release'
-        }
+          ember: 'release',
+        },
       },
       npm: {
         devDependencies: {
-          'ember-source': null
-        }
-      }
+          'ember-source': null,
+        },
+      },
     },
     {
       name: 'ember-beta',
       bower: {
         dependencies: {
-          'ember': 'components/ember#beta'
+          ember: 'components/ember#beta',
         },
         resolutions: {
-          'ember': 'beta'
-        }
+          ember: 'beta',
+        },
       },
       npm: {
         devDependencies: {
-          'ember-source': null
-        }
-      }
+          'ember-source': null,
+        },
+      },
     },
     {
       name: 'ember-canary',
       bower: {
         dependencies: {
-          'ember': 'components/ember#canary'
+          ember: 'components/ember#canary',
         },
         resolutions: {
-          'ember': 'canary'
-        }
+          ember: 'canary',
+        },
       },
       npm: {
         devDependencies: {
-          'ember-source': null
-        }
-      }
+          'ember-source': null,
+        },
+      },
     },
     {
       name: 'ember-default',
       npm: {
-        devDependencies: {}
-      }
-    }
-  ]
+        devDependencies: {},
+      },
+    },
+  ],
 };
diff --git a/blueprints/addon/files/addon-config/environment.js b/blueprints/addon/files/addon-config/environment.js
index 0dfaed472..9707ea62a 100644
--- a/blueprints/addon/files/addon-config/environment.js
+++ b/blueprints/addon/files/addon-config/environment.js
@@ -1,5 +1,5 @@
 'use strict';
 
 module.exports = function(/* environment, appConfig */) {
-  return { };
+  return {};
 };
diff --git a/blueprints/addon/files/index.js b/blueprints/addon/files/index.js
index 8eaaa2f0c..1fbb6a2a1 100644
--- a/blueprints/addon/files/index.js
+++ b/blueprints/addon/files/index.js
@@ -1,5 +1,5 @@
 'use strict';
 
 module.exports = {
-  name: '<%= addonModulePrefix %>'
+  name: '<%= addonModulePrefix %>',
 };
diff --git a/blueprints/app/files/.eslintrc.js b/blueprints/app/files/.eslintrc.js
index 450138401..e660d625f 100644
--- a/blueprints/app/files/.eslintrc.js
+++ b/blueprints/app/files/.eslintrc.js
@@ -2,13 +2,19 @@ module.exports = {
   root: true,
   parserOptions: {
     ecmaVersion: 2017,
-    sourceType: 'module'
+    sourceType: 'module',
   },
-  extends: 'eslint:recommended',
+  extends: ['eslint:recommended', 'prettier', 'plugin:ember/recommended'],
+  plugins: ['prettier', 'ember'],
   env: {
-    browser: true
+    browser: true,
   },
   rules: {
+    'prettier/prettier': ['error', {
+      singleQuote: true,
+      trailingComma: 'es5',
+      printWidth: 120,
+    }],
   },
   overrides: [
     // node files
@@ -18,15 +24,15 @@ module.exports = {
         'testem.js',
         'ember-cli-build.js',
         'config/**/*.js',
-        'tests/dummy/config/**/*.js'
+        'tests/dummy/config/**/*.js',
       ],
       parserOptions: {
         sourceType: 'script',
-        ecmaVersion: 2015
+        ecmaVersion: 2015,
       },
       env: {
         browser: false,
-        node: true
+        node: true,
       }
     },
 
@@ -35,8 +41,8 @@ module.exports = {
       files: ['tests/**/*.js'],
       excludedFiles: ['tests/dummy/**/*.js'],
       env: {
-        embertest: true
-      }
-    }
-  ]
+        embertest: true,
+      },
+    },
+  ],
 };
diff --git a/blueprints/app/files/app/app.js b/blueprints/app/files/app/app.js
index b3b2bd677..f08aaaf03 100644
--- a/blueprints/app/files/app/app.js
+++ b/blueprints/app/files/app/app.js
@@ -6,7 +6,7 @@ import config from './config/environment';
 const App = Application.extend({
   modulePrefix: config.modulePrefix,
   podModulePrefix: config.podModulePrefix,
-  Resolver
+  Resolver,
 });
 
 loadInitializers(App, config.modulePrefix);
diff --git a/blueprints/app/files/app/router.js b/blueprints/app/files/app/router.js
index d0bb00952..8f6f45989 100644
--- a/blueprints/app/files/app/router.js
+++ b/blueprints/app/files/app/router.js
@@ -3,10 +3,9 @@ import config from './config/environment';
 
 const Router = EmberRouter.extend({
   location: config.locationType,
-  rootURL: config.rootURL
+  rootURL: config.rootURL,
 });
 
-Router.map(function() {
-});
+Router.map(function() {});
 
 export default Router;
diff --git a/blueprints/app/files/config/environment.js b/blueprints/app/files/config/environment.js
index 1e14621c9..d8533ae56 100644
--- a/blueprints/app/files/config/environment.js
+++ b/blueprints/app/files/config/environment.js
@@ -13,14 +13,14 @@ module.exports = function(environment) {
       },
       EXTEND_PROTOTYPES: {
         // Prevent Ember Data from overriding Date.parse.
-        Date: false
-      }
+        Date: false,
+      },
     },
 
     APP: {
       // Here you can pass flags/options to your application instance
       // when it is created
-    }
+    },
   };
 
   if (environment === 'development') {
diff --git a/blueprints/app/files/config/targets.js b/blueprints/app/files/config/targets.js
index 082e68b51..071439de3 100644
--- a/blueprints/app/files/config/targets.js
+++ b/blueprints/app/files/config/targets.js
@@ -1,8 +1,3 @@
 module.exports = {
-  browsers: [
-    'ie 9',
-    'last 1 Chrome versions',
-    'last 1 Firefox versions',
-    'last 1 Safari versions'
-  ]
+  browsers: ['ie 9', 'last 1 Chrome versions', 'last 1 Firefox versions', 'last 1 Safari versions'],
 };
diff --git a/blueprints/app/files/package.json b/blueprints/app/files/package.json
index 37564ef61..a8522f7e8 100644
--- a/blueprints/app/files/package.json
+++ b/blueprints/app/files/package.json
@@ -36,7 +36,11 @@
     "ember-resolver": "^4.0.0",
     "ember-source": "~2.17.0-beta.2<% if (welcome) { %>",
     "ember-welcome-page": "^3.0.0<% } %>",
-    "loader.js": "^4.2.3"
+    "eslint-config-prettier": "^2.7.0",
+    "eslint-plugin-ember": "^5.0.0",
+    "eslint-plugin-prettier": "^2.3.1",
+    "loader.js": "^4.2.3",
+    "prettier": "^1.8.2"
   },
   "engines": {
     "node": "^4.5 || 6.* || >= 7.*"


Test patch:
diff --git a/blueprints/app/files/testem.js b/blueprints/app/files/testem.js
index 10ecc1045..219ca13fb 100644
--- a/blueprints/app/files/testem.js
+++ b/blueprints/app/files/testem.js
@@ -1,21 +1,12 @@
 module.exports = {
   test_page: 'tests/index.html?hidepassed',
   disable_watching: true,
-  launch_in_ci: [
-    'Chrome'
-  ],
-  launch_in_dev: [
-    'Chrome'
-  ],
+  launch_in_ci: ['Chrome'],
+  launch_in_dev: ['Chrome'],
   browser_args: {
     Chrome: {
       mode: 'ci',
-      args: [
-        '--disable-gpu',
-        '--headless',
-        '--remote-debugging-port=0',
-        '--window-size=1440,900'
-      ]
+      args: ['--disable-gpu', '--headless', '--remote-debugging-port=0', '--window-size=1440,900'],
     },
-  }
+  },
 };
diff --git a/blueprints/app/files/tests/helpers/module-for-acceptance.js b/blueprints/app/files/tests/helpers/module-for-acceptance.js
index 90a93bac2..364089288 100644
--- a/blueprints/app/files/tests/helpers/module-for-acceptance.js
+++ b/blueprints/app/files/tests/helpers/module-for-acceptance.js
@@ -16,6 +16,6 @@ export default function(name, options = {}) {
     afterEach() {
       let afterEach = options.afterEach && options.afterEach.apply(this, arguments);
       return resolve(afterEach).then(() => destroyApp(this.application));
-    }
+    },
   });
 }
diff --git a/tests/fixtures/addon/npm/config/ember-try.js b/tests/fixtures/addon/npm/config/ember-try.js
index 1c31c5491..1732ac436 100644
--- a/tests/fixtures/addon/npm/config/ember-try.js
+++ b/tests/fixtures/addon/npm/config/ember-try.js
@@ -4,71 +4,71 @@ module.exports = {
       name: 'ember-lts-2.12',
       npm: {
         devDependencies: {
-          'ember-source': '~2.12.0'
-        }
-      }
+          'ember-source': '~2.12.0',
+        },
+      },
     },
     {
       name: 'ember-lts-2.16',
       npm: {
         devDependencies: {
-          'ember-source': '~2.16.0'
-        }
-      }
+          'ember-source': '~2.16.0',
+        },
+      },
     },
     {
       name: 'ember-release',
       bower: {
         dependencies: {
-          'ember': 'components/ember#release'
+          ember: 'components/ember#release',
         },
         resolutions: {
-          'ember': 'release'
-        }
+          ember: 'release',
+        },
       },
       npm: {
         devDependencies: {
-          'ember-source': null
-        }
-      }
+          'ember-source': null,
+        },
+      },
     },
     {
       name: 'ember-beta',
       bower: {
         dependencies: {
-          'ember': 'components/ember#beta'
+          ember: 'components/ember#beta',
         },
         resolutions: {
-          'ember': 'beta'
-        }
+          ember: 'beta',
+        },
       },
       npm: {
         devDependencies: {
-          'ember-source': null
-        }
-      }
+          'ember-source': null,
+        },
+      },
     },
     {
       name: 'ember-canary',
       bower: {
         dependencies: {
-          'ember': 'components/ember#canary'
+          ember: 'components/ember#canary',
         },
         resolutions: {
-          'ember': 'canary'
-        }
+          ember: 'canary',
+        },
       },
       npm: {
         devDependencies: {
-          'ember-source': null
-        }
-      }
+          'ember-source': null,
+        },
+      },
     },
     {
       name: 'ember-default',
       npm: {
-        devDependencies: {}
-      }
-    }
-  ]
+        devDependencies: {},
+      },
+    },
+  ],
 };
diff --git a/tests/fixtures/addon/yarn/config/ember-try.js b/tests/fixtures/addon/yarn/config/ember-try.js
index 1a4a5bbd3..1de83a7f7 100644
--- a/tests/fixtures/addon/yarn/config/ember-try.js
+++ b/tests/fixtures/addon/yarn/config/ember-try.js
@@ -5,71 +5,71 @@ module.exports = {
       name: 'ember-lts-2.12',
       npm: {
         devDependencies: {
-          'ember-source': '~2.12.0'
-        }
-      }
+          'ember-source': '~2.12.0',
+        },
+      },
     },
     {
       name: 'ember-lts-2.16',
       npm: {
         devDependencies: {
-          'ember-source': '~2.16.0'
-        }
-      }
+          'ember-source': '~2.16.0',
+        },
+      },
     },
     {
       name: 'ember-release',
       bower: {
         dependencies: {
-          'ember': 'components/ember#release'
+          ember: 'components/ember#release',
         },
         resolutions: {
-          'ember': 'release'
-        }
+          ember: 'release',
+        },
       },
       npm: {
         devDependencies: {
-          'ember-source': null
-        }
-      }
+          'ember-source': null,
+        },
+      },
     },
     {
       name: 'ember-beta',
       bower: {
         dependencies: {
-          'ember': 'components/ember#beta'
+          ember: 'components/ember#beta',
         },
         resolutions: {
-          'ember': 'beta'
-        }
+          ember: 'beta',
+        },
       },
       npm: {
         devDependencies: {
-          'ember-source': null
-        }
-      }
+          'ember-source': null,
+        },
+      },
     },
     {
       name: 'ember-canary',
       bower: {
         dependencies: {
-          'ember': 'components/ember#canary'
+          ember: 'components/ember#canary',
         },
         resolutions: {
-          'ember': 'canary'
-        }
+          ember: 'canary',
+        },
       },
       npm: {
         devDependencies: {
-          'ember-source': null
-        }
-      }
+          'ember-source': null,
+        },
+      },
     },
     {
       name: 'ember-default',
       npm: {
-        devDependencies: {}
-      }
-    }
-  ]
+        devDependencies: {},
+      },
+    },
+  ],
 };