ember-cli / eslint-plugin-ember

An ESLint plugin that provides set of rules for Ember applications based on commonly known good practices.
MIT License
257 stars 198 forks source link
best-practices ember eslint eslint-plugin linting

eslint-plugin-ember

NPM version NPM downloads CI

An ESLint plugin that provides a set of rules for Ember applications based on commonly known good practices.

❗️Requirements

🚀 Usage

1. Install plugin

yarn add --dev eslint-plugin-ember

Or

npm install --save-dev eslint-plugin-ember

2. Update your config

// eslint.config.js (flat config)
const eslintPluginEmberRecommended = require('eslint-plugin-ember/configs/recommended');

module.exports = [
  ...eslintPluginEmberRecommended,
];

or

// .eslintrc.js (legacy config)
module.exports = {
  plugins: ['ember'],
  extends: [
    'eslint:recommended',
    'plugin:ember/recommended' // or other configuration
  ],
  rules: {
    // override / enable optional rules
    'ember/no-replace-test-comments': 'error'
  }
};

gts/gjs

lint files having First-Class Component Templates (fcct)

learn more here

[!NOTE] special care should be used when setting up parsers, since they cannot be overwritten. thus they should be used in override only and specific to file types

gjs/gts support is provided by the ember-eslint-parser

[!NOTE] if you import .gts files in .ts files, then ember-eslint-parser is required for .ts as well to enable typed linting

// .eslintrc.js
module.exports = {
  overrides: [
    {
      files: ['**/*.{js,ts}'],
      plugins: ['ember'],
      parser: '@typescript-eslint/parser',
      extends: [
        'eslint:recommended',
        'plugin:ember/recommended', // or other configuration
      ],
      rules: {
        // override / enable optional rules
        'ember/no-replace-test-comments': 'error'
      }
    },
    {
      files: ['**/*.gts'],
      parser: 'ember-eslint-parser',
      plugins: ['ember'],
      extends: [
        'eslint:recommended',
        'plugin:@typescript-eslint/recommended',
        'plugin:ember/recommended',
        'plugin:ember/recommended-gts',
      ],
    },
    {
      files: ['**/*.gjs'],
      parser: 'ember-eslint-parser',
      plugins: ['ember'],
      extends: [
        'eslint:recommended',
        'plugin:ember/recommended',
        'plugin:ember/recommended-gjs',
      ],
    },
    {
      files: ['tests/**/*.{js,ts,gjs,gts}'],
      rules: {
        // override / enable optional rules
        'ember/no-replace-test-comments': 'error'
      }
    },
  ],
};

rules applied to fcct templates

rules in templates can be disabled with eslint directives with mustache or html comments:

<template>
  <div>
    {{!eslint-disable-next-line}}
    {{test}}
  </div>
  <div>
    {{!--eslint-disable--}}
    {{test}}
    {{test}}
    {{test}}
    {{!--eslint-enable--}}
  </div>
</template>
<template>
  <div>
    <!--eslint-disable-next-line-->
    {{test}}
  </div>
  <div>
    <!-- eslint-disable -->
    {{test}}
    {{test}}
    {{test}}
    <!-- eslint-enable -->
  </div>
</template>

🧰 Configurations

Name
base
recommended
gjs logo recommended-gjs
gts logo recommended-gts

🍟 Rules

💼 Configurations enabled in.\ ✅ Set in the recommended configuration.\ gjs logo Set in the recommended-gjs configuration.\ gts logo Set in the recommended-gts configuration.\ 🔧 Automatically fixable by the --fix CLI option.\ 💡 Manually fixable by editor suggestions.

Components

Name                         Description 💼 🔧 💡
no-attrs-in-components disallow usage of this.attrs in components
no-attrs-snapshot disallow use of attrs snapshot in the didReceiveAttrs and didUpdateAttrs component hooks
no-classic-components enforce using Glimmer components
no-component-lifecycle-hooks disallow usage of "classic" ember component lifecycle hooks. Render modifiers or custom functional modifiers should be used instead.
no-on-calls-in-components disallow usage of on to call lifecycle hooks in components
require-tagless-components disallow using the wrapper element of a component

Computed Properties

Name                                                            Description 💼 🔧 💡
computed-property-getters enforce the consistent use of getters in computed properties
no-arrow-function-computed-properties disallow arrow functions in computed properties
no-assignment-of-untracked-properties-used-in-tracking-contexts disallow assignment of untracked properties that are used as computed property dependencies 🔧
no-computed-properties-in-native-classes disallow using computed properties in native classes
no-deeply-nested-dependent-keys-with-each disallow usage of deeply-nested computed property dependent keys with @each
no-duplicate-dependent-keys disallow repeating computed property dependent keys 🔧
no-incorrect-computed-macros disallow incorrect usage of computed property macros 🔧
no-invalid-dependent-keys disallow invalid dependent keys in computed properties 🔧
no-side-effects disallow unexpected side effects in computed properties
no-volatile-computed-properties disallow volatile computed properties
require-computed-macros require using computed property macros when possible 🔧
require-computed-property-dependencies require dependencies to be declared statically in computed properties 🔧
require-return-from-computed disallow missing return statements in computed properties
use-brace-expansion enforce usage of brace expansion in computed property dependent keys

Controllers

Name Description 💼 🔧 💡
alias-model-in-controller enforce aliasing model in controllers
avoid-using-needs-in-controllers disallow using needs in controllers
no-controllers disallow non-essential controllers

Deprecations

Name Description 💼 🔧 💡
closure-actions enforce usage of closure actions
new-module-imports enforce using "New Module Imports" from Ember RFC #176
no-array-prototype-extensions disallow usage of Ember's Array prototype extensions 🔧
no-at-ember-render-modifiers disallow importing from @ember/render-modifiers
no-deprecated-router-transition-methods enforce usage of router service transition methods 🔧
no-function-prototype-extensions disallow usage of Ember's function prototype extensions
no-implicit-injections enforce usage of implicit service injections 🔧
no-mixins disallow the usage of mixins
no-new-mixins disallow the creation of new mixins
no-observers disallow usage of observers
no-old-shims disallow usage of old shims for modules 🔧
no-string-prototype-extensions disallow usage of String prototype extensions

Ember Data

Name                           Description 💼 🔧 💡
no-empty-attrs disallow usage of empty attributes in Ember Data models
use-ember-data-rfc-395-imports enforce usage of @ember-data/ package imports instead ember-data 🔧

Ember Object

Name                                 Description 💼 🔧 💡
avoid-leaking-state-in-ember-objects disallow state leakage
no-get require using ES5 getters instead of Ember's get / getProperties functions 🔧
no-get-with-default disallow usage of the Ember's getWithDefault function 🔧
no-proxies disallow using array or object proxies
no-try-invoke disallow usage of the Ember's tryInvoke util
require-super-in-lifecycle-hooks require super to be called in lifecycle hooks 🔧
use-ember-get-and-set enforce usage of Ember.get and Ember.set 🔧

Ember Octane

Name                                 Description 💼 🔧 💡
classic-decorator-hooks enforce using correct hooks for both classic and non-classic classes
classic-decorator-no-classic-methods disallow usage of classic APIs such as get/set in classes that aren't explicitly decorated with @classic
no-actions-hash disallow the actions hash in components, controllers, and routes
no-classic-classes disallow "classic" classes in favor of native JS classes
no-ember-super-in-es-classes disallow use of this._super in ES class methods 🔧
no-empty-glimmer-component-classes disallow empty backing classes for Glimmer components
no-tracked-properties-from-args disallow creating @tracked properties from this.args
template-indent enforce consistent indentation for gts/gjs templates 🔧
template-no-let-reference disallow referencing let variables in \<template> gjs logo gts logo

jQuery

Name Description 💼 🔧 💡
jquery-ember-run disallow usage of jQuery without an Ember run loop
no-global-jquery disallow usage of global jQuery object
no-jquery disallow any usage of jQuery

Miscellaneous

Name                                               Description 💼 🔧 💡
named-functions-in-promises enforce usage of named functions in promises
no-html-safe disallow the use of htmlSafe
no-incorrect-calls-with-inline-anonymous-functions disallow inline anonymous functions as arguments to debounce, once, and scheduleOnce
no-invalid-debug-function-arguments disallow usages of Ember's assert() / warn() / deprecate() functions that have the arguments passed in the wrong order.
no-restricted-property-modifications disallow modifying the specified properties 🔧
no-runloop disallow usage of @ember/runloop functions
require-fetch-import enforce explicit import for fetch()

Routes

Name                             Description 💼 🔧 💡
no-capital-letters-in-routes disallow routes with uppercased letters in router.js
no-controller-access-in-routes disallow routes from accessing the controller outside of setupController/resetController
no-private-routing-service disallow injecting the private routing service
no-shadow-route-definition enforce no route path definition shadowing
no-unnecessary-index-route disallow unnecessary index route definition
no-unnecessary-route-path-option disallow unnecessary usage of the route path option 🔧
route-path-style enforce usage of kebab-case (instead of snake_case or camelCase) in route paths 💡
routes-segments-snake-case enforce usage of snake_cased dynamic segments in routes

Services

Name                                      Description 💼 🔧 💡
no-implicit-service-injection-argument disallow omitting the injected service name argument 🔧
no-restricted-service-injections disallow injecting certain services under certain paths
no-unnecessary-service-injection-argument disallow unnecessary argument when injecting services 🔧
no-unused-services disallow unused service injections (see rule doc for limitations) 💡

Stylistic Issues

Name Description 💼 🔧 💡
order-in-components enforce proper order of properties in components 🔧
order-in-controllers enforce proper order of properties in controllers 🔧
order-in-models enforce proper order of properties in models 🔧
order-in-routes enforce proper order of properties in routes 🔧

Testing

Name                                       Description 💼 🔧 💡
no-current-route-name disallow usage of the currentRouteName() test helper
no-ember-testing-in-module-scope disallow use of Ember.testing in module scope
no-invalid-test-waiters disallow incorrect usage of test waiter APIs
no-legacy-test-waiters disallow the use of the legacy test waiter APIs
no-noop-setup-on-error-in-before disallows using no-op setupOnerror in before or beforeEach 🔧
no-pause-test disallow usage of the pauseTest helper in tests
no-replace-test-comments disallow 'Replace this with your real tests' comments in test files
no-restricted-resolver-tests disallow the use of patterns that use the restricted resolver in tests
no-settled-after-test-helper disallow usage of await settled() right after test helper that calls it internally 🔧
no-test-and-then disallow usage of the andThen test wait helper
no-test-import-export disallow importing of "-test.js" in a test file and exporting from a test file
no-test-module-for disallow usage of moduleFor, moduleForComponent, etc
no-test-support-import disallow importing of "test-support" files in production code.
no-test-this-render disallow usage of the this.render in tests, recommending to use @ember/test-helpers' render instead.
prefer-ember-test-helpers enforce usage of @ember/test-helpers methods over native window methods
require-valid-css-selector-in-test-helpers disallow using invalid CSS selectors in test helpers 🔧

🍻 Contribution Guide

If you have any suggestions, ideas, or problems, feel free to create an issue, but first please make sure your question does not repeat previous ones.

Creating a New Rule

Note that new rules should not immediately be added to the recommended configuration, as we only consider such breaking changes during major version updates.

🔓 License

See the LICENSE file for license rights and limitations (MIT).