diff --git a/.gitignore b/.gitignore index 3e88eb2cce..bc16c6be0c 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,4 @@ npm-debug.log # eslint-remote-tester eslint-remote-tester-results +package-lock.json diff --git a/README.md b/README.md index 7f28e984ba..9ffcfab0d9 100644 --- a/README.md +++ b/README.md @@ -110,6 +110,27 @@ module.exports = { }; ``` +### Strict Template Linting (Optional) + +For enhanced template linting in `gjs`/`gts` files, use the `strict-gjs` or `strict-gts` configs. These include additional template rules ported from `ember-template-lint`: + +```javascript +// eslint.config.js +const ember = require('eslint-plugin-ember'); + +module.exports = [ + ...ember.configs.recommended, + { + files: ['**/*.gts'], + extends: ['plugin:ember/strict-gts'], + }, + { + files: ['**/*.gjs'], + extends: ['plugin:ember/strict-gjs'], + }, +]; +``` + ### rules applied to fcct templates - semi rule, same as [prettier plugin](https://github.com/gitKrystan/prettier-plugin-ember-template-tag/issues/1) @@ -160,6 +181,8 @@ rules in templates can be disabled with eslint directives with mustache or html | ✅ | `recommended` | | ![gjs logo](/docs/svgs/gjs.svg) | `recommended-gjs` | | ![gts logo](/docs/svgs/gts.svg) | `recommended-gts` | +| | `strict-gjs` | +| | `strict-gts` | @@ -174,6 +197,114 @@ rules in templates can be disabled with eslint directives with mustache or html 🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\ 💡 Manually fixable by [editor suggestions](https://eslint.org/docs/latest/use/core-concepts#rule-suggestions). +### Accessibility + +| Name                                            | Description | 💼 | 🔧 | 💡 | +| :--------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------- | :------------------------------------------ | :- | :- | +| [template-link-href-attributes](docs/rules/template-link-href-attributes.md) | require href attribute on link elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-abstract-roles](docs/rules/template-no-abstract-roles.md) | disallow abstract ARIA roles | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-accesskey-attribute](docs/rules/template-no-accesskey-attribute.md) | disallow accesskey attribute | ![badge-strict-gjs][] ![badge-strict-gts][] | 🔧 | | +| [template-no-aria-hidden-body](docs/rules/template-no-aria-hidden-body.md) | disallow aria-hidden on body element | ![badge-strict-gjs][] ![badge-strict-gts][] | 🔧 | | +| [template-no-aria-unsupported-elements](docs/rules/template-no-aria-unsupported-elements.md) | disallow ARIA roles, states, and properties on elements that do not support them | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-autofocus-attribute](docs/rules/template-no-autofocus-attribute.md) | disallow autofocus attribute | ![badge-strict-gjs][] ![badge-strict-gts][] | 🔧 | | +| [template-no-down-event-binding](docs/rules/template-no-down-event-binding.md) | disallow mouse down event bindings | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-duplicate-landmark-elements](docs/rules/template-no-duplicate-landmark-elements.md) | disallow duplicate landmark elements without unique labels | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-empty-headings](docs/rules/template-no-empty-headings.md) | disallow empty heading elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-heading-inside-button](docs/rules/template-no-heading-inside-button.md) | disallow heading elements inside button elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-invalid-aria-attributes](docs/rules/template-no-invalid-aria-attributes.md) | disallow invalid aria-* attributes | | | | +| [template-no-invalid-interactive](docs/rules/template-no-invalid-interactive.md) | disallow non-interactive elements with interactive handlers | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-invalid-link-text](docs/rules/template-no-invalid-link-text.md) | disallow invalid or uninformative link text content | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-invalid-link-title](docs/rules/template-no-invalid-link-title.md) | disallow invalid title attributes on link elements | | | | +| [template-no-invalid-role](docs/rules/template-no-invalid-role.md) | disallow invalid ARIA roles | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-nested-interactive](docs/rules/template-no-nested-interactive.md) | disallow nested interactive elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-nested-landmark](docs/rules/template-no-nested-landmark.md) | disallow nested landmark elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-pointer-down-event-binding](docs/rules/template-no-pointer-down-event-binding.md) | disallow pointer down event bindings | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-positive-tabindex](docs/rules/template-no-positive-tabindex.md) | disallow positive tabindex values | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-redundant-landmark-role](docs/rules/template-no-redundant-landmark-role.md) | disallow redundant landmark roles that are implicit on HTML elements | ![badge-strict-gjs][] ![badge-strict-gts][] | 🔧 | | +| [template-no-unsupported-role-attributes](docs/rules/template-no-unsupported-role-attributes.md) | disallow ARIA attributes that are not supported by the element role | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-require-aria-activedescendant-tabindex](docs/rules/template-require-aria-activedescendant-tabindex.md) | require elements with aria-activedescendant to be tabbable (have tabindex) | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-require-context-role](docs/rules/template-require-context-role.md) | require ARIA roles to be used in appropriate context | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-require-iframe-title](docs/rules/template-require-iframe-title.md) | require iframe elements to have a title attribute | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-require-input-label](docs/rules/template-require-input-label.md) | require label for form input elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-require-lang-attribute](docs/rules/template-require-lang-attribute.md) | require lang attribute on html element | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-require-mandatory-role-attributes](docs/rules/template-require-mandatory-role-attributes.md) | require mandatory ARIA attributes for ARIA roles | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-require-media-caption](docs/rules/template-require-media-caption.md) | require captions for audio and video elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-require-presentational-children](docs/rules/template-require-presentational-children.md) | require presentational elements to only contain presentational children | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-require-valid-alt-text](docs/rules/template-require-valid-alt-text.md) | require valid alt text for images | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-table-groups](docs/rules/template-table-groups.md) | require table elements to use table grouping elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | + +### Best Practices + +| Name                                               | Description | 💼 | 🔧 | 💡 | +| :--------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------- | :------------------------------------------ | :- | :- | +| [template-no-action-modifiers](docs/rules/template-no-action-modifiers.md) | disallow usage of {{action}} modifiers | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-action-on-submit-button](docs/rules/template-no-action-on-submit-button.md) | disallow action attribute on submit buttons | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-ambiguous-glimmer-paths](docs/rules/template-no-ambiguous-glimmer-paths.md) | disallow ambiguous path in templates | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-args-paths](docs/rules/template-no-args-paths.md) | disallow @args in paths | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-arguments-for-html-elements](docs/rules/template-no-arguments-for-html-elements.md) | disallow @arguments on HTML elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-array-prototype-extensions](docs/rules/template-no-array-prototype-extensions.md) | disallow usage of Ember Array prototype extensions | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-at-ember-render-modifiers](docs/rules/template-no-at-ember-render-modifiers.md) | disallow usage of @ember/render-modifiers | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-attribute-splat-on-html-element](docs/rules/template-no-attribute-splat-on-html-element.md) | disallow ...attributes on HTML elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-attrs-splat](docs/rules/template-no-attrs-splat.md) | disallow attribute splat on components | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-bare-strings](docs/rules/template-no-bare-strings.md) | disallow bare strings in templates (require translation/localization) | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-bare-yield](docs/rules/template-no-bare-yield.md) | disallow {{yield}} without parameters outside of contextual components | | | | +| [template-no-block-params](docs/rules/template-no-block-params.md) | disallow yielding/invoking a component block without parameters | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-block-params-for-html-elements](docs/rules/template-no-block-params-for-html-elements.md) | disallow block params on HTML elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-builtin-form-components](docs/rules/template-no-builtin-form-components.md) | disallow usage of built-in form components | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-capital-arguments](docs/rules/template-no-capital-arguments.md) | disallow capital arguments (use lowercase @arg instead of @Arg) | | | | +| [template-no-chained-this](docs/rules/template-no-chained-this.md) | disallow chained property access on this | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-class-bindings](docs/rules/template-no-class-bindings.md) | disallow usage of class attribute bindings | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-curly-component-invocation](docs/rules/template-no-curly-component-invocation.md) | disallow curly component invocation | | | | +| [template-no-debugger](docs/rules/template-no-debugger.md) | disallow {{debugger}} in templates | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-duplicate-attributes](docs/rules/template-no-duplicate-attributes.md) | disallow duplicate attribute names in templates | ![badge-strict-gjs][] ![badge-strict-gts][] | 🔧 | | +| [template-no-duplicate-id](docs/rules/template-no-duplicate-id.md) | disallow duplicate id attributes | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-dynamic-subexpression-invocations](docs/rules/template-no-dynamic-subexpression-invocations.md) | disallow dynamic subexpression invocations | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-element-event-actions](docs/rules/template-no-element-event-actions.md) | disallow element event actions (use {{on}} modifier instead) | | | | +| [template-no-extra-mut-helpers](docs/rules/template-no-extra-mut-helpers.md) | disallow unnecessary mut helpers | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-forbidden-elements](docs/rules/template-no-forbidden-elements.md) | disallow specific HTML elements | | | | +| [template-no-html-comments](docs/rules/template-no-html-comments.md) | disallow HTML comments in templates | | | | +| [template-no-implicit-this](docs/rules/template-no-implicit-this.md) | require explicit `this` in property access | | | | +| [template-no-inline-event-handlers](docs/rules/template-no-inline-event-handlers.md) | disallow DOM event handler attributes | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-inline-linkto](docs/rules/template-no-inline-linkto.md) | disallow inline form of LinkTo component | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-inline-styles](docs/rules/template-no-inline-styles.md) | disallow inline styles | | | | +| [template-no-input-block](docs/rules/template-no-input-block.md) | disallow block usage of {{input}} helper | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-input-placeholder](docs/rules/template-no-input-placeholder.md) | disallow placeholder attribute on input elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-input-tagname](docs/rules/template-no-input-tagname.md) | disallow tagName attribute on {{input}} helper | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-invalid-meta](docs/rules/template-no-invalid-meta.md) | disallow invalid meta tags | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-log](docs/rules/template-no-log.md) | disallow {{log}} in templates | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-model-argument-in-route-templates](docs/rules/template-no-model-argument-in-route-templates.md) | disallow @model argument in route templates | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-multiple-empty-lines](docs/rules/template-no-multiple-empty-lines.md) | disallow multiple consecutive empty lines in templates | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-mut-helper](docs/rules/template-no-mut-helper.md) | disallow usage of (mut) helper | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-negated-comparison](docs/rules/template-no-negated-comparison.md) | disallow negated comparisons in templates | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-negated-condition](docs/rules/template-no-negated-condition.md) | disallow negated conditions in if/unless | | | | +| [template-no-nested-splattributes](docs/rules/template-no-nested-splattributes.md) | disallow nested ...attributes usage | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-obscure-array-access](docs/rules/template-no-obscure-array-access.md) | disallow obscure array access patterns like `objectPath.@each.property` | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-obsolete-elements](docs/rules/template-no-obsolete-elements.md) | disallow obsolete HTML elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-outlet-outside-routes](docs/rules/template-no-outlet-outside-routes.md) | disallow {{outlet}} outside of route templates | | | | +| [template-no-page-title-component](docs/rules/template-no-page-title-component.md) | disallow usage of ember-page-title component | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-passed-in-event-handlers](docs/rules/template-no-passed-in-event-handlers.md) | disallow passing event handlers directly as component arguments | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-positional-data-test-selectors](docs/rules/template-no-positional-data-test-selectors.md) | disallow positional data-test selectors | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-potential-path-strings](docs/rules/template-no-potential-path-strings.md) | disallow potential path strings in templates | | | | +| [template-no-redundant-fn](docs/rules/template-no-redundant-fn.md) | disallow unnecessary usage of (fn) helper | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-this-in-template-only-components](docs/rules/template-no-this-in-template-only-components.md) | disallow this in template-only components (gjs/gts) | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-trailing-spaces](docs/rules/template-no-trailing-spaces.md) | disallow trailing whitespace at the end of lines in templates | ![badge-strict-gjs][] ![badge-strict-gts][] | 🔧 | | +| [template-no-unnecessary-component-helper](docs/rules/template-no-unnecessary-component-helper.md) | disallow unnecessary component helper | | | | +| [template-no-unnecessary-concat](docs/rules/template-no-unnecessary-concat.md) | disallow unnecessary string concatenation | ![badge-strict-gjs][] ![badge-strict-gts][] | 🔧 | | +| [template-no-unnecessary-curly-parens](docs/rules/template-no-unnecessary-curly-parens.md) | disallow unnecessary curlies around single values | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-unnecessary-service-injection-argument](docs/rules/template-no-unnecessary-service-injection-argument.md) | disallow unnecessary service injection argument | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-unused-block-params](docs/rules/template-no-unused-block-params.md) | disallow unused block parameters in templates | | | | +| [template-no-valueless-arguments](docs/rules/template-no-valueless-arguments.md) | disallow valueless named arguments | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-whitespace-for-layout](docs/rules/template-no-whitespace-for-layout.md) | disallow using whitespace for layout purposes | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-yield-only](docs/rules/template-no-yield-only.md) | disallow components that only yield | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-yield-to-default](docs/rules/template-no-yield-to-default.md) | disallow yield to default block | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-require-button-type](docs/rules/template-require-button-type.md) | require button elements to have a valid type attribute | ![badge-strict-gjs][] ![badge-strict-gts][] | 🔧 | | +| [template-require-each-key](docs/rules/template-require-each-key.md) | require key attribute in {{#each}} loops | | | | +| [template-require-has-block-helper](docs/rules/template-require-has-block-helper.md) | require (has-block) helper usage instead of hasBlock property | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-self-closing-void-elements](docs/rules/template-self-closing-void-elements.md) | require self-closing on void elements | ![badge-strict-gjs][] ![badge-strict-gts][] | 🔧 | | +| [template-simple-unless](docs/rules/template-simple-unless.md) | require simple conditions in unless blocks | | | | +| [template-splat-attributes-only](docs/rules/template-splat-attributes-only.md) | disallow ...spread other than ...attributes | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-style-concatenation](docs/rules/template-style-concatenation.md) | disallow string concatenation in inline styles | ![badge-strict-gjs][] ![badge-strict-gts][] | | | + ### Components | Name                         | Description | 💼 | 🔧 | 💡 | @@ -215,20 +346,31 @@ rules in templates can be disabled with eslint directives with mustache or html ### Deprecations -| Name | Description | 💼 | 🔧 | 💡 | -| :----------------------------------------------------------------------------------------------- | :-------------------------------------------------------- | :- | :- | :- | -| [closure-actions](docs/rules/closure-actions.md) | enforce usage of closure actions | ✅ | | | -| [new-module-imports](docs/rules/new-module-imports.md) | enforce using "New Module Imports" from Ember RFC #176 | ✅ | | | -| [no-array-prototype-extensions](docs/rules/no-array-prototype-extensions.md) | disallow usage of Ember's `Array` prototype extensions | | 🔧 | | -| [no-at-ember-render-modifiers](docs/rules/no-at-ember-render-modifiers.md) | disallow importing from @ember/render-modifiers | ✅ | | | -| [no-deprecated-router-transition-methods](docs/rules/no-deprecated-router-transition-methods.md) | enforce usage of router service transition methods | ✅ | 🔧 | | -| [no-function-prototype-extensions](docs/rules/no-function-prototype-extensions.md) | disallow usage of Ember's `function` prototype extensions | ✅ | | | -| [no-implicit-injections](docs/rules/no-implicit-injections.md) | enforce usage of implicit service injections | ✅ | 🔧 | | -| [no-mixins](docs/rules/no-mixins.md) | disallow the usage of mixins | ✅ | | | -| [no-new-mixins](docs/rules/no-new-mixins.md) | disallow the creation of new mixins | ✅ | | | -| [no-observers](docs/rules/no-observers.md) | disallow usage of observers | ✅ | | | -| [no-old-shims](docs/rules/no-old-shims.md) | disallow usage of old shims for modules | ✅ | 🔧 | | -| [no-string-prototype-extensions](docs/rules/no-string-prototype-extensions.md) | disallow usage of `String` prototype extensions | ✅ | | | +| Name | Description | 💼 | 🔧 | 💡 | +| :----------------------------------------------------------------------------------------------- | :-------------------------------------------------------- | :------------------------------------------ | :- | :- | +| [closure-actions](docs/rules/closure-actions.md) | enforce usage of closure actions | ✅ | | | +| [new-module-imports](docs/rules/new-module-imports.md) | enforce using "New Module Imports" from Ember RFC #176 | ✅ | | | +| [no-array-prototype-extensions](docs/rules/no-array-prototype-extensions.md) | disallow usage of Ember's `Array` prototype extensions | | 🔧 | | +| [no-at-ember-render-modifiers](docs/rules/no-at-ember-render-modifiers.md) | disallow importing from @ember/render-modifiers | ✅ | | | +| [no-deprecated-router-transition-methods](docs/rules/no-deprecated-router-transition-methods.md) | enforce usage of router service transition methods | ✅ | 🔧 | | +| [no-function-prototype-extensions](docs/rules/no-function-prototype-extensions.md) | disallow usage of Ember's `function` prototype extensions | ✅ | | | +| [no-implicit-injections](docs/rules/no-implicit-injections.md) | enforce usage of implicit service injections | ✅ | 🔧 | | +| [no-mixins](docs/rules/no-mixins.md) | disallow the usage of mixins | ✅ | | | +| [no-new-mixins](docs/rules/no-new-mixins.md) | disallow the creation of new mixins | ✅ | | | +| [no-observers](docs/rules/no-observers.md) | disallow usage of observers | ✅ | | | +| [no-old-shims](docs/rules/no-old-shims.md) | disallow usage of old shims for modules | ✅ | 🔧 | | +| [no-string-prototype-extensions](docs/rules/no-string-prototype-extensions.md) | disallow usage of `String` prototype extensions | ✅ | | | +| [template-deprecated-inline-view-helper](docs/rules/template-deprecated-inline-view-helper.md) | disallow inline {{view}} helper | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-deprecated-render-helper](docs/rules/template-deprecated-render-helper.md) | disallow {{render}} helper | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-action](docs/rules/template-no-action.md) | disallow {{action}} helper | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-attrs-in-components](docs/rules/template-no-attrs-in-components.md) | disallow attrs in component templates | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-form-action](docs/rules/template-no-form-action.md) | disallow usage of action attribute on form elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-link-to-positional-params](docs/rules/template-no-link-to-positional-params.md) | disallow positional params in LinkTo component | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-link-to-tagname](docs/rules/template-no-link-to-tagname.md) | disallow tagName attribute on LinkTo component | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-partial](docs/rules/template-no-partial.md) | disallow {{partial}} helper | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-route-action](docs/rules/template-no-route-action.md) | disallow usage of route-action helper | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-unbound](docs/rules/template-no-unbound.md) | disallow {{unbound}} helper | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-with](docs/rules/template-no-with.md) | disallow {{with}} helper | ![badge-strict-gjs][] ![badge-strict-gts][] | | | ### Ember Data @@ -284,6 +426,15 @@ rules in templates can be disabled with eslint directives with mustache or html | [no-runloop](docs/rules/no-runloop.md) | disallow usage of `@ember/runloop` functions | ✅ | | | | [require-fetch-import](docs/rules/require-fetch-import.md) | enforce explicit import for `fetch()` | | | | +### Possible Errors + +| Name | Description | 💼 | 🔧 | 💡 | +| :------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------- | :------------------------------------------ | :- | :- | +| [template-no-scope-outside-table-headings](docs/rules/template-no-scope-outside-table-headings.md) | disallow scope attribute outside th/td elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-shadowed-elements](docs/rules/template-no-shadowed-elements.md) | disallow shadowing of built-in HTML elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-unbalanced-curlies](docs/rules/template-no-unbalanced-curlies.md) | disallow unbalanced mustache curlies | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-no-unknown-arguments-for-builtin-components](docs/rules/template-no-unknown-arguments-for-builtin-components.md) | disallow unknown arguments for built-in components | | | | + ### Routes | Name                             | Description | 💼 | 🔧 | 💡 | @@ -297,6 +448,13 @@ rules in templates can be disabled with eslint directives with mustache or html | [route-path-style](docs/rules/route-path-style.md) | enforce usage of kebab-case (instead of snake_case or camelCase) in route paths | | | 💡 | | [routes-segments-snake-case](docs/rules/routes-segments-snake-case.md) | enforce usage of snake_cased dynamic segments in routes | ✅ | | | +### Security + +| Name                       | Description | 💼 | 🔧 | 💡 | +| :--------------------------------------------------------------------- | :-------------------------------------------------------------- | :------------------------------------------ | :- | :- | +| [template-link-rel-noopener](docs/rules/template-link-rel-noopener.md) | require rel="noopener noreferrer" on links with target="_blank" | ![badge-strict-gjs][] ![badge-strict-gts][] | 🔧 | | +| [template-no-triple-curlies](docs/rules/template-no-triple-curlies.md) | disallow usage of triple curly brackets (unescaped variables) | ![badge-strict-gjs][] ![badge-strict-gts][] | | | + ### Services | Name                                      | Description | 💼 | 🔧 | 💡 | @@ -306,14 +464,29 @@ rules in templates can be disabled with eslint directives with mustache or html | [no-unnecessary-service-injection-argument](docs/rules/no-unnecessary-service-injection-argument.md) | disallow unnecessary argument when injecting services | | 🔧 | | | [no-unused-services](docs/rules/no-unused-services.md) | disallow unused service injections (see rule doc for limitations) | | | 💡 | +### Style + +| Name | Description | 💼 | 🔧 | 💡 | +| :----------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------- | :- | :- | :- | +| [template-no-quoteless-attributes](docs/rules/template-no-quoteless-attributes.md) | require quotes on all attribute values | | 🔧 | | +| [template-no-unnecessary-curly-in-string-attrs](docs/rules/template-no-unnecessary-curly-in-string-attrs.md) | disallow unnecessary curly braces in attributes | | | | +| [template-no-unnecessary-curly-strings](docs/rules/template-no-unnecessary-curly-strings.md) | disallow unnecessary curly braces in string interpolations | | | | +| [template-no-whitespace-within-word](docs/rules/template-no-whitespace-within-word.md) | disallow whitespace within mustache or block expressions | | | | + ### Stylistic Issues -| Name | Description | 💼 | 🔧 | 💡 | -| :--------------------------------------------------------- | :------------------------------------------------ | :- | :- | :- | -| [order-in-components](docs/rules/order-in-components.md) | enforce proper order of properties in components | | 🔧 | | -| [order-in-controllers](docs/rules/order-in-controllers.md) | enforce proper order of properties in controllers | | 🔧 | | -| [order-in-models](docs/rules/order-in-models.md) | enforce proper order of properties in models | | 🔧 | | -| [order-in-routes](docs/rules/order-in-routes.md) | enforce proper order of properties in routes | | 🔧 | | +| Name                           | Description | 💼 | 🔧 | 💡 | +| :----------------------------------------------------------------------------- | :------------------------------------------------------------- | :------------------------------------------ | :- | :- | +| [order-in-components](docs/rules/order-in-components.md) | enforce proper order of properties in components | | 🔧 | | +| [order-in-controllers](docs/rules/order-in-controllers.md) | enforce proper order of properties in controllers | | 🔧 | | +| [order-in-models](docs/rules/order-in-models.md) | enforce proper order of properties in models | | 🔧 | | +| [order-in-routes](docs/rules/order-in-routes.md) | enforce proper order of properties in routes | | 🔧 | | +| [template-attribute-indentation](docs/rules/template-attribute-indentation.md) | enforce consistent attribute indentation in templates | | 🔧 | | +| [template-attribute-order](docs/rules/template-attribute-order.md) | enforce consistent ordering of attributes in template elements | ![badge-strict-gjs][] ![badge-strict-gts][] | | | +| [template-block-indentation](docs/rules/template-block-indentation.md) | enforce consistent block indentation in templates | | 🔧 | | +| [template-eol-last](docs/rules/template-eol-last.md) | require newline at end of template files | ![badge-strict-gjs][] ![badge-strict-gts][] | 🔧 | | +| [template-linebreak-style](docs/rules/template-linebreak-style.md) | enforce consistent linebreak style in templates | | 🔧 | | +| [template-quotes](docs/rules/template-quotes.md) | enforce consistent quote style in templates | | 🔧 | | ### Testing @@ -360,3 +533,6 @@ Note that new rules should not immediately be added to the [recommended](./lib/r ## 🔓 License See the [LICENSE](LICENSE.md) file for license rights and limitations (MIT). + +[badge-strict-gjs]: https://img.shields.io/badge/strict--gjs-blue +[badge-strict-gts]: https://img.shields.io/badge/strict--gts-blue diff --git a/docs/rules/template-attribute-indentation.md b/docs/rules/template-attribute-indentation.md new file mode 100644 index 0000000000..2ba112658a --- /dev/null +++ b/docs/rules/template-attribute-indentation.md @@ -0,0 +1,33 @@ +# ember/template-attribute-indentation + +🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). + + + +Enforces consistent attribute indentation in templates. + +This is a stylistic rule that is disabled by default. + +## Rule Details + +This rule enforces consistent indentation for attributes in template elements. + +## Examples + +Examples of **correct** code for this rule: + +```gjs + +``` + +```gjs + +``` + +## References + +- [ember-template-lint attribute-indentation](https://github.com/ember-template-lint/ember-template-lint/blob/master/docs/rule/attribute-indentation.md) diff --git a/docs/rules/template-attribute-order.md b/docs/rules/template-attribute-order.md new file mode 100644 index 0000000000..d366dbf3a2 --- /dev/null +++ b/docs/rules/template-attribute-order.md @@ -0,0 +1,70 @@ +# ember/template-attribute-order + +💼 This rule is enabled in the following [configs](https://github.com/ember-cli/eslint-plugin-ember#-configurations): `strict-gjs`, `strict-gts`. + + + +Enforces a consistent ordering of attributes in template elements. This helps improve readability and maintainability of templates. + +## Rule Details + +This rule enforces a consistent order for attributes on template elements. By default, it follows this order: + +1. `class` +2. `id` +3. `role` +4. `aria-*` attributes +5. `data-test-*` attributes +6. `type` +7. `name` +8. `value` +9. `placeholder` +10. `disabled` + +## Examples + +Examples of **incorrect** code for this rule: + +```gjs + +``` + +```gjs + +``` + +Examples of **correct** code for this rule: + +```gjs + +``` + +```gjs + +``` + +## Configuration + +You can customize the order by providing an `order` array: + +```js +module.exports = { + rules: { + 'ember/template-attribute-order': ['error', { + order: ['class', 'id', 'role', 'aria-', 'type'] + }] + } +}; +``` + +## References + +- [ember-template-lint attribute-order](https://github.com/ember-template-lint/ember-template-lint/blob/master/docs/rule/attribute-order.md) diff --git a/docs/rules/template-block-indentation.md b/docs/rules/template-block-indentation.md new file mode 100644 index 0000000000..a522ecc5d2 --- /dev/null +++ b/docs/rules/template-block-indentation.md @@ -0,0 +1,35 @@ +# ember/template-block-indentation + +🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). + + + +Enforces consistent block indentation in templates. + +This is a stylistic rule that is disabled by default. + +## Rule Details + +This rule enforces consistent indentation for block statements in templates. + +## Examples + +Examples of **correct** code for this rule: + +```gjs + +``` + +```gjs + +``` + +## References + +- [ember-template-lint block-indentation](https://github.com/ember-template-lint/ember-template-lint/blob/master/docs/rule/block-indentation.md) diff --git a/docs/rules/template-deprecated-inline-view-helper.md b/docs/rules/template-deprecated-inline-view-helper.md new file mode 100644 index 0000000000..c7c7a17935 --- /dev/null +++ b/docs/rules/template-deprecated-inline-view-helper.md @@ -0,0 +1,13 @@ +# ember/template-deprecated-inline-view-helper + +💼 This rule is enabled in the following [configs](https://github.com/ember-cli/eslint-plugin-ember#-configurations): `strict-gjs`, `strict-gts`. + + + +## Examples + +See ember-template-lint documentation. + +## References + +- [ember-template-lint](https://github.com/ember-template-lint/ember-template-lint) diff --git a/docs/rules/template-deprecated-render-helper.md b/docs/rules/template-deprecated-render-helper.md new file mode 100644 index 0000000000..59cd7a7eb2 --- /dev/null +++ b/docs/rules/template-deprecated-render-helper.md @@ -0,0 +1,25 @@ +# ember/template-deprecated-render-helper + +💼 This rule is enabled in the following [configs](https://github.com/ember-cli/eslint-plugin-ember#-configurations): `strict-gjs`, `strict-gts`. + + + +Disallows the {{render}} helper which is deprecated. + +## Examples + +Incorrect: + +```gjs + +``` + +Correct: + +```gjs + +``` + +## References + +- [ember-template-lint deprecated-render-helper](https://github.com/ember-template-lint/ember-template-lint/blob/master/docs/rule/deprecated-render-helper.md) diff --git a/docs/rules/template-eol-last.md b/docs/rules/template-eol-last.md new file mode 100644 index 0000000000..dd4b3bdcba --- /dev/null +++ b/docs/rules/template-eol-last.md @@ -0,0 +1,73 @@ +# ember/template-eol-last + +💼 This rule is enabled in the following [configs](https://github.com/ember-cli/eslint-plugin-ember#-configurations): `strict-gjs`, `strict-gts`. + +🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). + + + +Requires or disallows newline at the end of template files. + +Consistent handling of line endings at the end of files helps maintain clean diffs in version control. + +## Rule Details + +This rule enforces a newline (or lack thereof) at the end of template blocks. + +## Examples + +Examples of **incorrect** code for this rule with default `"always"` option: + +```gjs +// Missing newline at end + +``` + +Examples of **correct** code for this rule with default `"always"` option: + +```gjs + + +``` + +Examples of **incorrect** code for this rule with `"never"` option: + +```gjs +// Unwanted newline at end + + +``` + +Examples of **correct** code for this rule with `"never"` option: + +```gjs + +``` + +## Configuration + +This rule takes one option: + +- `"always"` (default): requires a newline at the end +- `"never"`: disallows a newline at the end + +```js +module.exports = { + rules: { + 'ember/template-eol-last': ['error', 'always'] + } +}; +``` + +## References + +- [ember-template-lint eol-last](https://github.com/ember-template-lint/ember-template-lint/blob/master/docs/rule/eol-last.md) +- [ESLint eol-last](https://eslint.org/docs/rules/eol-last) diff --git a/docs/rules/template-linebreak-style.md b/docs/rules/template-linebreak-style.md new file mode 100644 index 0000000000..73952d3f00 --- /dev/null +++ b/docs/rules/template-linebreak-style.md @@ -0,0 +1,27 @@ +# ember/template-linebreak-style + +🔧 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix). + + + +Enforces consistent linebreak style in templates. + +This is a stylistic rule that is disabled by default. + +## Rule Details + +This rule enforces consistent linebreak style (LF or CRLF) in templates. + +## Examples + +Examples of **correct** code for this rule: + +```gjs + +``` + +## References + +- [ember-template-lint linebreak-style](https://github.com/ember-template-lint/ember-template-lint/blob/master/docs/rule/linebreak-style.md) diff --git a/docs/rules/template-link-href-attributes.md b/docs/rules/template-link-href-attributes.md new file mode 100644 index 0000000000..c848edccd0 --- /dev/null +++ b/docs/rules/template-link-href-attributes.md @@ -0,0 +1,61 @@ +# ember/template-link-href-attributes + +💼 This rule is enabled in the following [configs](https://github.com/ember-cli/eslint-plugin-ember#-configurations): `strict-gjs`, `strict-gts`. + + + +Requires `href` attribute on `` elements. + +Anchor elements should have an `href` attribute to be properly recognized as links by browsers and assistive technologies. If an element is meant to be interactive but not navigate, use a `