npm.io
13.4.0 • Published 1 week ago

eslint-plugin-ember

Licence
MIT
Version
13.4.0
Deps
17
Size
1.1 MB
Vulns
0
Weekly
198.6K
Stars
263

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
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 at ember-template-imports

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

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
  • semi rule, same as prettier plugin
  • no-undef rule will take effect for template vars (includes js scope)
  • no-unused rule will take effect for template block params

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>

Migrating from ember-template-lint

If you are replacing ember-template-lint with this plugin, use the template-lint-migration config to get the equivalent set of rules:

// eslint.config.js (flat config)
import eslintPluginEmberRecommended from 'eslint-plugin-ember/configs/recommended';
import eslintPluginEmberTemplateLintMigration from 'eslint-plugin-ember/configs/template-lint-migration';

export default [
  ...eslintPluginEmberRecommended,
  ...eslintPluginEmberTemplateLintMigration,
  {
    rules: {
      // Migrate custom overrides from your .template-lintrc.*:
      'ember/template-no-bare-strings': ['error', { allowlist: ['×'] }],
      'ember/template-no-inline-styles': 'off',
    },
  },
];

template-lint-migration mirrors the ember-template-lint recommended preset.

Linting .hbs files

ESLint flat config only picks up .hbs files when a files glob names them. Add a dedicated block so they route to the Handlebars parser:

// eslint.config.mjs
import { hbsParser, plugin as emberPlugin } from 'eslint-plugin-ember/recommended';

export default [
  // ...other blocks...
  {
    files: ['app/**/*.hbs'],
    languageOptions: { parser: hbsParser },
    plugins: { ember: emberPlugin },
    rules: {
      'ember/template-no-bare-strings': 'error',
      // ...other template rules...
    },
  },
];

Make sure no earlier @typescript-eslint/parser block's files glob reaches .hbs — narrow it to ['**/*.{js,ts,gjs,gts}'] (or similar). Flat config merges rules across every matching block, so even if our HBS block overrides the parser, type-info rules from a matching TS block still layer on and fail with errors like:

Parsing error: was not found by the project service because the extension for the file (.hbs) is non-standard.

or

Error while loading rule @typescript-eslint/await-thenable: You have used a rule which requires type information.

Replacing template-lint-disable comments

Inline disable directives need to be rewritten to ESLint's syntax, prefixed with ember/template-. For now, only two scopes are supported: the next line, or the rest of the file. For example, replace:

{{!template-lint-disable no-invalid-role}}

with:

{{!eslint-disable-next-line ember/template-no-invalid-role}}

The template-no-template-lint-directives rule (enabled by the template-lint-migration config) does this rewrite for you: run eslint --fix once and it converts every template-lint-disable / template-lint-enable comment in your templates.

To disable a rule for an entire .gjs/.gts file, use a regular ESLint file-level directive in the JS region — it applies to the <template> contents as well:

/* eslint-disable ember/template-no-invalid-role */

<template>
  <div role="range"></div>
</template>

Configurations

Name
base
recommended
gjs logo recommended-gjs
gts logo recommended-gts
template-lint-migration

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.
Set in the template-lint-migration configuration.
Automatically fixable by the --fix CLI option.
Manually fixable by editor suggestions.

Accessibility
Name Description
template-link-href-attributes require href attribute on link elements
template-no-abstract-roles disallow abstract ARIA roles
template-no-accesskey-attribute disallow accesskey attribute
template-no-aria-hidden-body disallow aria-hidden on body element
template-no-aria-unsupported-elements disallow ARIA roles, states, and properties on elements that do not support them
template-no-autofocus-attribute disallow autofocus attribute
template-no-duplicate-landmark-elements disallow duplicate landmark elements without unique labels
template-no-empty-headings disallow empty heading elements
template-no-heading-inside-button disallow heading elements inside button elements
template-no-invalid-aria-attributes disallow invalid aria-* attributes
template-no-invalid-interactive disallow non-interactive elements with interactive handlers
template-no-invalid-link-text disallow invalid or uninformative link text content
template-no-invalid-link-title disallow invalid title attributes on link elements
template-no-invalid-role disallow invalid ARIA roles
template-no-nested-interactive disallow nested interactive elements
template-no-nested-landmark disallow nested landmark elements
template-no-pointer-down-event-binding disallow pointer down event bindings
template-no-positive-tabindex disallow positive tabindex values
template-no-redundant-role disallow redundant role attributes
template-no-unsupported-role-attributes disallow ARIA attributes that are not supported by the element role
template-no-whitespace-within-word disallow excess whitespace within words (e.g. "W e l c o m e")
template-require-aria-activedescendant-tabindex require non-interactive elements with aria-activedescendant to have tabindex
template-require-context-role require ARIA roles to be used in appropriate context
template-require-iframe-title require iframe elements to have a title attribute
template-require-input-label require label for form input elements
template-require-lang-attribute require lang attribute on html element
template-require-mandatory-role-attributes require mandatory ARIA attributes for ARIA roles
template-require-media-caption require captions for audio and video elements
template-require-presentational-children require presentational elements to only contain presentational children
template-require-valid-alt-text require valid alt text for images and other elements
template-require-valid-form-groups require grouped form controls to have fieldset/legend or WAI-ARIA group labeling
template-table-groups require table elements to use table grouping elements
Best Practices
Name Description
template-builtin-component-arguments disallow setting certain attributes on builtin components
template-no-action-modifiers disallow usage of {{action}} modifiers
template-no-action-on-submit-button disallow action attribute on submit buttons
template-no-args-paths disallow args.foo paths in templates, use @foo instead
template-no-arguments-for-html-elements disallow @arguments on HTML elements
template-no-array-prototype-extensions disallow usage of Ember Array prototype extensions
template-no-at-ember-render-modifiers disallow usage of @ember/render-modifiers
template-no-bare-strings disallow bare strings in templates (require translation/localization)
template-no-bare-yield disallow templates whose only meaningful content is a bare {{yield}}
template-no-block-params-for-html-elements disallow block params on HTML elements
template-no-builtin-form-components disallow usage of built-in form components
template-no-capital-arguments disallow capital arguments (use lowercase @arg instead of @Arg)
template-no-chained-this disallow redundant this.this in templates
template-no-class-bindings disallow passing classBinding or classNameBindings as arguments in templates
template-no-curly-component-invocation disallow curly component invocation, use angle bracket syntax instead
template-no-debugger disallow {{debugger}} in templates
template-no-duplicate-attributes disallow duplicate attribute names in templates
template-no-duplicate-id disallow duplicate id attributes
template-no-dynamic-subexpression-invocations disallow dynamic subexpression invocations
template-no-element-event-actions disallow element event actions (use {{on}} modifier instead)
template-no-forbidden-elements disallow specific HTML elements
template-no-html-comments disallow HTML comments in templates
template-no-implicit-this require explicit this in property access
template-no-index-component-invocation disallow index component invocations
template-no-inline-event-handlers disallow DOM event handler attributes
template-no-inline-linkto disallow inline form of LinkTo component
template-no-inline-styles disallow inline styles
template-no-input-block disallow block usage of {{input}} helper
template-no-input-tagname disallow tagName attribute on {{input}} helper
template-no-invalid-meta disallow invalid meta tags
template-no-log disallow {{log}} in templates
template-no-model-argument-in-route-templates disallow @model argument in route templates
template-no-multiple-empty-lines disallow multiple consecutive empty lines in templates
template-no-mut-helper disallow usage of (mut) helper
template-no-negated-condition disallow negated conditions in if/unless
template-no-nested-splattributes disallow nested ...attributes usage
template-no-obscure-array-access disallow obscure array access patterns like objectPath.@each.property
template-no-obsolete-elements disallow obsolete HTML elements
template-no-outlet-outside-routes disallow {{outlet}} outside of route templates
template-no-page-title-component disallow usage of ember-page-title component
template-no-passed-in-event-handlers disallow passing event handlers directly as component arguments
template-no-positional-data-test-selectors disallow positional data-test-* params in curly invocations
template-no-potential-path-strings disallow potential path strings in attribute values
template-no-redundant-fn disallow unnecessary usage of (fn) helper
template-no-restricted-invocations disallow certain components, helpers or modifiers from being used
template-no-splattributes-with-class disallow splattributes with class attribute
template-no-template-lint-directives disallow {{! template-lint-* }} directives (use the {{! eslint-* }} equivalents)
template-no-this-in-template-only-components disallow this in template-only components
template-no-trailing-spaces disallow trailing whitespace at the end of lines in templates
template-no-unavailable-this disallow this in templates that are not inside a class or function
template-no-unnecessary-component-helper disallow unnecessary component helper
template-no-unnecessary-concat disallow unnecessary string concatenation
template-no-unnecessary-curly-parens disallow unnecessary parentheses enclosing statements in curlies
template-no-unused-block-params disallow unused block parameters in templates
template-no-valueless-arguments disallow valueless named arguments
template-no-whitespace-for-layout disallow using whitespace for layout purposes
template-no-yield-block-params-to-else-inverse disallow yielding block params to else or inverse block
template-no-yield-only disallow components that only yield
template-no-yield-to-default disallow yield to default block
template-require-button-type require button elements to have a valid type attribute
template-require-each-key require key attribute in {{#each}} loops
template-require-form-method require form method attribute
template-require-has-block-helper require (has-block) helper usage instead of hasBlock property
template-require-iframe-src-attribute require iframe elements to have src attribute
template-require-input-type require input elements to have a valid type attribute
template-require-splattributes require splattributes usage in component templates
template-require-strict-mode require templates to be in strict mode
template-require-valid-named-block-naming-format require valid named block naming format
template-self-closing-void-elements require self-closing on void elements
template-simple-modifiers require simple modifier syntax
template-simple-unless require simple conditions in unless blocks
template-sort-invocations require sorted attributes and modifiers
template-splat-attributes-only disallow ...spread other than ...attributes
template-style-concatenation disallow string concatenation in inline styles
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-builtin-form-components disallow usage of built-in form components
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
template-deprecated-inline-view-helper disallow inline {{view}} helper
template-deprecated-render-helper disallow {{render}} helper
template-no-action disallow {{action}} helper
template-no-attrs-in-components disallow attrs in component templates
template-no-link-to-positional-params disallow positional params in LinkTo component
template-no-link-to-tagname disallow tagName attribute on LinkTo component
template-no-route-action disallow usage of route-action helper
template-no-unbound disallow {{unbound}} helper
template-no-with disallow {{with}} helper
Ember Data
Name Description
no-empty-attrs disallow usage of empty attributes in Ember Data models
require-async-inverse-relationship require inverse to be specified in @belongsTo and @hasMany decorators
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-modifier-argument-destructuring disallow destructuring of modifier arguments to avoid consuming tracked data too early
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-built-ins enforce usage of @ember/reactive/collections imports instead of tracked-built-ins
no-tracked-properties-from-args disallow creating @tracked properties from this.args
template-no-deprecated disallow using deprecated Glimmer components, helpers, and modifiers in 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()
Possible Errors
Name Description
template-no-extra-mut-helper-argument disallow passing more than one argument to the mut helper
template-no-jsx-attributes disallow JSX-style camelCase attributes
template-no-scope-outside-table-headings disallow scope attribute outside th elements
template-no-shadowed-elements disallow ambiguity with block param names shadowing HTML elements
template-no-unbalanced-curlies disallow unbalanced mustache curlies
template-no-unknown-arguments-for-builtin-components disallow unknown arguments for built-in components
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
Security
Name Description
template-link-rel-noopener require rel="noopener noreferrer" on links with target="_blank"
template-no-triple-curlies disallow usage of triple curly brackets (unescaped variables)
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)
Style
Name Description
template-no-quoteless-attributes require quotes on all attribute values
template-no-unnecessary-curly-strings disallow unnecessary curly braces in string interpolations
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
template-attribute-indentation enforce proper indentation of attributes and arguments in multi-line templates
template-attribute-order enforce consistent ordering of attributes in template elements
template-block-indentation enforce consistent indentation for block statements and their children
template-eol-last require or disallow newline at the end of template files
template-linebreak-style enforce consistent linebreaks in templates
template-modifier-name-case require dasherized names for modifiers
template-no-only-default-slot disallow using only the default slot
template-quotes enforce consistent quote style in templates
template-template-length enforce template size constraints
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
  • Create an issue with a description of the proposed rule
  • Create files for the new rule:
    • lib/rules/new-rule.js (implementation, see no-proxies for an example)
    • docs/rules/new-rule.md (documentation, start from the template -- raw, rendered)
    • tests/lib/rules/new-rule.js (tests, see no-proxies for an example)
  • Run pnpm update to automatically update the README and other files (and re-run this if you change the rule name or description)
  • Make sure your changes will pass CI by running:
    • pnpm test
    • pnpm lint (pnpm lint:js --fix can fix many errors)
  • Create a PR and link the created issue in the description

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).

Keywords