1 | # ember-template-lint
|
2 |
|
3 | [![npm version](https://badge.fury.io/js/ember-template-lint.svg)](https://badge.fury.io/js/ember-template-lint)
|
4 | [![Build Status](https://github.com/ember-template-lint/ember-template-lint/workflows/CI/badge.svg)](https://github.com/ember-template-lint/ember-template-lint/actions?query=workflow%3ACI)
|
5 |
|
6 | ember-template-lint will lint your handlebars template and return error results.
|
7 |
|
8 | For example, given the rule [`no-bare-strings`](docs/rule/no-bare-strings.md) is enabled, this template would be
|
9 | in violation:
|
10 |
|
11 | ```hbs
|
12 | {{!-- app/components/my-thing/template.hbs --}}
|
13 | <div>A bare string</div>
|
14 | ```
|
15 |
|
16 | When the `ember-template-lint` executable is run, we would have a single result indicating that
|
17 | the `no-bare-strings` rule found an error.
|
18 |
|
19 | ## Installation
|
20 |
|
21 | This addon is installed by default with new Ember apps, so check your package.json before installing to see if you need to install it.
|
22 |
|
23 | To install ember-template-lint
|
24 |
|
25 | With npm:
|
26 |
|
27 | ```bash
|
28 | npm install --save-dev ember-template-lint
|
29 | ```
|
30 |
|
31 | With yarn:
|
32 |
|
33 | ```bash
|
34 | yarn add ember-template-lint --dev
|
35 | ```
|
36 |
|
37 | Node.js `10 || >=12` is required.
|
38 |
|
39 | ## Usage
|
40 |
|
41 | While `ember-template-lint` does have a [Node API](docs/node-api.md), the main way to use it is through its executable, which is intended to be installed locally within a project.
|
42 |
|
43 | Basic usage is as straightforward as
|
44 |
|
45 | ```bash
|
46 | ember-template-lint .
|
47 | ```
|
48 |
|
49 | ### Workflow Examples
|
50 |
|
51 | Basic usage with a single file
|
52 |
|
53 | ```bash
|
54 | ember-template-lint "app/templates/application.hbs"
|
55 | ```
|
56 |
|
57 | Output errors with source description
|
58 |
|
59 | ```bash
|
60 | ember-template-lint "app/templates/application.hbs" --verbose
|
61 | ```
|
62 |
|
63 | Multiple file/directory/wildcard paths are accepted
|
64 |
|
65 | ```bash
|
66 | ember-template-lint "app/templates/components/**/*" "app/templates/application.hbs"
|
67 | ```
|
68 |
|
69 | Output errors as pretty-printed JSON string
|
70 |
|
71 | ```bash
|
72 | ember-template-lint "app/templates/application.hbs" --json
|
73 | ```
|
74 |
|
75 | Ignore warnings / only report errors
|
76 |
|
77 | ```bash
|
78 | ember-template-lint "app/templates/application.hbs" --quiet
|
79 | ```
|
80 |
|
81 | Define custom config path
|
82 |
|
83 | ```bash
|
84 | ember-template-lint "app/templates/application.hbs" --config-path .my-template-lintrc.js
|
85 | ```
|
86 |
|
87 | Read from stdin
|
88 |
|
89 | ```bash
|
90 | ember-template-lint --filename app/templates/application.hbs < app/templates/application.hbs
|
91 | ```
|
92 |
|
93 | Print list of formatted rules for use with `pending` in config file
|
94 |
|
95 | ```bash
|
96 | ember-template-lint "app/templates/application.hbs" --print-pending
|
97 | ```
|
98 |
|
99 | Specify custom ignore pattern `['**/dist/**', '**/tmp/**', '**/node_modules/**']` by default
|
100 |
|
101 | ```bash
|
102 | ember-template-lint "/tmp/template.hbs" --ignore-pattern "**/foo/**" --ignore-pattern "**/bar/**"
|
103 | ```
|
104 |
|
105 | Disable ignore pattern entirely
|
106 |
|
107 | ```bash
|
108 | ember-template-lint "/tmp/template.hbs" --no-ignore-pattern
|
109 | ```
|
110 |
|
111 | Running a single rule without options
|
112 |
|
113 | ```bash
|
114 | ember-template-lint --no-config-path app/templates --rule 'no-implicit-this:error'
|
115 | ```
|
116 |
|
117 | Running a single rule with options
|
118 |
|
119 | ```bash
|
120 | ember-template-lint --no-config-path app/templates --rule 'no-implicit-this:["error", { "allow": ["some-helper"] }]'
|
121 | ```
|
122 |
|
123 | Running a single rule, disabling inline configuration
|
124 |
|
125 | ```bash
|
126 | ember-template-lint --no-config-path app/templates --rule 'no-implicit-this:error' --no-inline-config
|
127 | ```
|
128 |
|
129 | Specify a config object to use instead of what exists locally
|
130 |
|
131 | ```bash
|
132 | ember-template-lint --config '{ "rules": { "no-implicit-this": { "severity": 2, "config": true } } }' test/fixtures/no-implicit-this-allow-with-regexp/app/templates
|
133 | ```
|
134 |
|
135 | :bulb: Ensure you wrap all glob patterns in quotes so that it won't be interpreted by the CLI. `ember-template-lint app/templates/**` (this will expand all paths in app/templates) and `ember-template-lint "app/templates/**"` (this will pass the glob to ember-template-lint and not interpret the glob).
|
136 |
|
137 | ## Configuration
|
138 |
|
139 | ### Project Wide
|
140 |
|
141 | You can turn on specific rules by toggling them in a
|
142 | `.template-lintrc.js` file at the base of your project, or at a custom relative
|
143 | path which may be identified using the CLI:
|
144 |
|
145 | ```javascript
|
146 | module.exports = {
|
147 | extends: 'recommended',
|
148 |
|
149 | rules: {
|
150 | 'no-bare-strings': true,
|
151 | },
|
152 | };
|
153 | ```
|
154 |
|
155 | For more detailed information see [configuration](docs/configuration.md).
|
156 |
|
157 | ### Presets
|
158 |
|
159 | | | Name | Description |
|
160 | | :----------------- | :--------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
161 | | :white_check_mark: | [recommended](lib/config/recommended.js) | enables the recommended rules |
|
162 | | :car: | [octane](lib/config/octane.js) | extends the `recommended` preset by enabling Ember Octane rules |
|
163 | | :nail_care: | [stylistic](lib/config/stylistic.js) | enables stylistic rules for those who aren't ready to adopt [ember-template-lint-plugin-prettier](https://github.com/ember-template-lint/ember-template-lint-plugin-prettier) (including stylistic rules that were previously in the `recommended` preset in ember-template-lint v1) |
|
164 |
|
165 | ## Rules
|
166 |
|
167 | Each rule has emojis denoting:
|
168 |
|
169 | - what configuration it belongs to
|
170 | - :wrench: if some problems reported by the rule are automatically fixable by the `--fix` command line option
|
171 |
|
172 |
|
173 |
|
174 | | | Rule ID |
|
175 | | :------------------------- | :-------------------------------------------------------------------------------------------------------- |
|
176 | | | [attribute-indentation](./docs/rule/attribute-indentation.md) |
|
177 | | :nail_care: | [block-indentation](./docs/rule/block-indentation.md) |
|
178 | | | [builtin-component-arguments](./docs/rule/builtin-component-arguments.md) |
|
179 | | | [deprecated-each-syntax](./docs/rule/deprecated-each-syntax.md) |
|
180 | | | [deprecated-inline-view-helper](./docs/rule/deprecated-inline-view-helper.md) |
|
181 | | :white_check_mark: | [deprecated-render-helper](./docs/rule/deprecated-render-helper.md) |
|
182 | | :nail_care: | [eol-last](./docs/rule/eol-last.md) |
|
183 | | :wrench: | [inline-link-to](./docs/rule/inline-link-to.md) |
|
184 | | :nail_care: | [linebreak-style](./docs/rule/linebreak-style.md) |
|
185 | | :white_check_mark: | [link-href-attributes](./docs/rule/link-href-attributes.md) |
|
186 | | :white_check_mark::wrench: | [link-rel-noopener](./docs/rule/link-rel-noopener.md) |
|
187 | | | [modifier-name-case](./docs/rule/modifier-name-case.md) |
|
188 | | :white_check_mark: | [no-abstract-roles](./docs/rule/no-abstract-roles.md) |
|
189 | | :wrench: | [no-accesskey-attribute](./docs/rule/no-accesskey-attribute.md) |
|
190 | | :car: | [no-action](./docs/rule/no-action.md) |
|
191 | | | [no-action-modifiers](./docs/rule/no-action-modifiers.md) |
|
192 | | :white_check_mark: | [no-args-paths](./docs/rule/no-args-paths.md) |
|
193 | | | [no-arguments-for-html-elements](./docs/rule/no-arguments-for-html-elements.md) |
|
194 | | :wrench: | [no-aria-hidden-body](./docs/rule/no-aria-hidden-body.md) |
|
195 | | :white_check_mark: | [no-attrs-in-components](./docs/rule/no-attrs-in-components.md) |
|
196 | | | [no-bare-strings](./docs/rule/no-bare-strings.md) |
|
197 | | | [no-block-params-for-html-elements](./docs/rule/no-block-params-for-html-elements.md) |
|
198 | | | [no-capital-arguments](./docs/rule/no-capital-arguments.md) |
|
199 | | :car: | [no-curly-component-invocation](./docs/rule/no-curly-component-invocation.md) |
|
200 | | :white_check_mark: | [no-debugger](./docs/rule/no-debugger.md) |
|
201 | | | [no-down-event-binding](./docs/rule/no-down-event-binding.md) |
|
202 | | :white_check_mark: | [no-duplicate-attributes](./docs/rule/no-duplicate-attributes.md) |
|
203 | | | [no-duplicate-id](./docs/rule/no-duplicate-id.md) |
|
204 | | | [no-duplicate-landmark-elements](./docs/rule/no-duplicate-landmark-elements.md) |
|
205 | | | [no-dynamic-subexpression-invocations](./docs/rule/no-dynamic-subexpression-invocations.md) |
|
206 | | | [no-element-event-actions](./docs/rule/no-element-event-actions.md) |
|
207 | | :white_check_mark: | [no-extra-mut-helper-argument](./docs/rule/no-extra-mut-helper-argument.md) |
|
208 | | | [no-forbidden-elements](./docs/rule/no-forbidden-elements.md) |
|
209 | | | [no-heading-inside-button](./docs/rule/no-heading-inside-button.md) |
|
210 | | :white_check_mark: | [no-html-comments](./docs/rule/no-html-comments.md) |
|
211 | | :car: | [no-implicit-this](./docs/rule/no-implicit-this.md) |
|
212 | | :white_check_mark: | [no-index-component-invocation](./docs/rule/no-index-component-invocation.md) |
|
213 | | :white_check_mark: | [no-inline-styles](./docs/rule/no-inline-styles.md) |
|
214 | | :white_check_mark: | [no-input-block](./docs/rule/no-input-block.md) |
|
215 | | :white_check_mark: | [no-input-tagname](./docs/rule/no-input-tagname.md) |
|
216 | | | [no-invalid-block-param-definition](./docs/rule/no-invalid-block-param-definition.md) |
|
217 | | :white_check_mark: | [no-invalid-interactive](./docs/rule/no-invalid-interactive.md) |
|
218 | | :white_check_mark: | [no-invalid-link-text](./docs/rule/no-invalid-link-text.md) |
|
219 | | | [no-invalid-link-title](./docs/rule/no-invalid-link-title.md) |
|
220 | | :white_check_mark: | [no-invalid-meta](./docs/rule/no-invalid-meta.md) |
|
221 | | :white_check_mark: | [no-invalid-role](./docs/rule/no-invalid-role.md) |
|
222 | | | [no-link-to-tagname](./docs/rule/no-link-to-tagname.md) |
|
223 | | :white_check_mark: | [no-log](./docs/rule/no-log.md) |
|
224 | | :wrench: | [no-model-argument-in-route-templates](./docs/rule/no-model-argument-in-route-templates.md) |
|
225 | | :nail_care: | [no-multiple-empty-lines](./docs/rule/no-multiple-empty-lines.md) |
|
226 | | | [no-mut-helper](./docs/rule/no-mut-helper.md) |
|
227 | | :white_check_mark: | [no-negated-condition](./docs/rule/no-negated-condition.md) |
|
228 | | :white_check_mark: | [no-nested-interactive](./docs/rule/no-nested-interactive.md) |
|
229 | | | [no-nested-landmark](./docs/rule/no-nested-landmark.md) |
|
230 | | | [no-nested-splattributes](./docs/rule/no-nested-splattributes.md) |
|
231 | | :white_check_mark: | [no-obsolete-elements](./docs/rule/no-obsolete-elements.md) |
|
232 | | :white_check_mark: | [no-outlet-outside-routes](./docs/rule/no-outlet-outside-routes.md) |
|
233 | | :white_check_mark: | [no-partial](./docs/rule/no-partial.md) |
|
234 | | | [no-passed-in-event-handlers](./docs/rule/no-passed-in-event-handlers.md) |
|
235 | | :wrench: | [no-positional-data-test-selectors](./docs/rule/no-positional-data-test-selectors.md) |
|
236 | | :white_check_mark: | [no-positive-tabindex](./docs/rule/no-positive-tabindex.md) |
|
237 | | | [no-potential-path-strings](./docs/rule/no-potential-path-strings.md) |
|
238 | | :white_check_mark: | [no-quoteless-attributes](./docs/rule/no-quoteless-attributes.md) |
|
239 | | :wrench: | [no-redundant-fn](./docs/rule/no-redundant-fn.md) |
|
240 | | :wrench: | [no-redundant-landmark-role](./docs/rule/no-redundant-landmark-role.md) |
|
241 | | | [no-restricted-invocations](./docs/rule/no-restricted-invocations.md) |
|
242 | | :white_check_mark: | [no-shadowed-elements](./docs/rule/no-shadowed-elements.md) |
|
243 | | :wrench: | [no-this-in-template-only-components](./docs/rule/no-this-in-template-only-components.md) |
|
244 | | :nail_care: | [no-trailing-spaces](./docs/rule/no-trailing-spaces.md) |
|
245 | | :white_check_mark: | [no-triple-curlies](./docs/rule/no-triple-curlies.md) |
|
246 | | | [no-unbalanced-curlies](./docs/rule/no-unbalanced-curlies.md) |
|
247 | | :white_check_mark: | [no-unbound](./docs/rule/no-unbound.md) |
|
248 | | | [no-unknown-arguments-for-builtin-components](./docs/rule/no-unknown-arguments-for-builtin-components.md) |
|
249 | | :white_check_mark: | [no-unnecessary-component-helper](./docs/rule/no-unnecessary-component-helper.md) |
|
250 | | :nail_care: | [no-unnecessary-concat](./docs/rule/no-unnecessary-concat.md) |
|
251 | | :white_check_mark: | [no-unused-block-params](./docs/rule/no-unused-block-params.md) |
|
252 | | | [no-whitespace-for-layout](./docs/rule/no-whitespace-for-layout.md) |
|
253 | | | [no-whitespace-within-word](./docs/rule/no-whitespace-within-word.md) |
|
254 | | | [no-yield-only](./docs/rule/no-yield-only.md) |
|
255 | | | [no-yield-to-default](./docs/rule/no-yield-to-default.md) |
|
256 | | :nail_care: | [quotes](./docs/rule/quotes.md) |
|
257 | | :white_check_mark::wrench: | [require-button-type](./docs/rule/require-button-type.md) |
|
258 | | | [require-each-key](./docs/rule/require-each-key.md) |
|
259 | | | [require-form-method](./docs/rule/require-form-method.md) |
|
260 | | :wrench: | [require-has-block-helper](./docs/rule/require-has-block-helper.md) |
|
261 | | :white_check_mark: | [require-iframe-title](./docs/rule/require-iframe-title.md) |
|
262 | | | [require-input-label](./docs/rule/require-input-label.md) |
|
263 | | | [require-lang-attribute](./docs/rule/require-lang-attribute.md) |
|
264 | | | [require-splattributes](./docs/rule/require-splattributes.md) |
|
265 | | :white_check_mark: | [require-valid-alt-text](./docs/rule/require-valid-alt-text.md) |
|
266 | | :nail_care: | [self-closing-void-elements](./docs/rule/self-closing-void-elements.md) |
|
267 | | :white_check_mark: | [simple-unless](./docs/rule/simple-unless.md) |
|
268 | | | [splat-attributes-only](./docs/rule/splat-attributes-only.md) |
|
269 | | :white_check_mark: | [style-concatenation](./docs/rule/style-concatenation.md) |
|
270 | | :white_check_mark: | [table-groups](./docs/rule/table-groups.md) |
|
271 | | | [template-length](./docs/rule/template-length.md) |
|
272 |
|
273 |
|
274 |
|
275 | ### Supporting the `--fix` option
|
276 |
|
277 | You can add a fixer to a rule. See [fixer documentation](docs/fixer.md) for more details.
|
278 |
|
279 | ### Sharing configs
|
280 |
|
281 | It is possible to share a config (`extends`) or plugin (custom rules) across projects. See [ember-template-lint-plugin-peopleconnect](https://github.com/peopleconnectus/ember-template-lint-plugin-peopleconnect) for an example.
|
282 |
|
283 | ## Defining your own rules
|
284 |
|
285 | You can define and use your own custom rules using the plugin system. See [plugin documentation](docs/plugins.md) for more details.
|
286 |
|
287 | ## Semantic Versioning Policy
|
288 |
|
289 | The semver policy for this addon can be read here: [semver policy](dev/versioning.md).
|
290 |
|
291 | ## Contributing
|
292 |
|
293 | See the [Contributing Guidelines](CONTRIBUTING.md) for information on how to help out.
|
294 |
|
295 | ## License
|
296 |
|
297 | This project is licensed under the [MIT License](LICENSE.md).
|