ember-template-lint
ember-template-lint copied to clipboard
Can a plugin specify overrides?
Background
When the latest versions of ember-template-lint
(v5.3.0
) and ember-template-lint-plugin-prettier
(v4.1.0
) are installed, template code in test files will be checked for formatting. Running yarn lint:hbs:fix
will auto-format the code.
However, the indentations are currently suboptimal. In addition, reformatting increases the lines of code (LOC) changed in the pull request that updates ember-template-lint
to v5
. Thus, an end-developer may want to turn off auto-formatting in test files.
How to turn off auto-formatting
Suppose an end-developer has a shared configuration file (e.g. to maintain a monorepo). There are two approaches: one, where the developer uses require
to read the file, and another, where they write a plugin and extend it.
Approach 1: Use require
to read the file
/* Shared */
'use strict';
module.exports = {
plugins: ['ember-template-lint-plugin-prettier'],
extends: ['recommended', 'ember-template-lint-plugin-prettier:recommended'],
overrides: [
{
files: ['tests/**/*-test.{js,ts}'],
rules: {
prettier: 'off',
},
},
],
};
/* Consuming project */
module.exports = require('some-namespace/ember-template-lint');
Approach 2: Use extends
to extend a plugin
/* Shared */
'use strict';
module.exports = {
name: 'my-shared-plugin',
rules: {},
configurations: {
recommended: {
plugins: ['ember-template-lint-plugin-prettier'],
extends: ['recommended', 'ember-template-lint-plugin-prettier:recommended'],
overrides: [
{
files: ['tests/**/*-test.{js,ts}'],
rules: {
prettier: 'off',
},
},
],
},
},
};
/* Consuming project */
module.exports = {
plugins: ['some-namespace/ember-template-lint'],
extends: 'my-shared-plugin:recommended'
};
Problem
In Approach 1, the overrides
key correctly prevents auto-formatting the template code in test files. In Approach 2, however, the plugin's overrides
is not respected.
Preliminary investigation
Depending on the approach, we get a different config
from getProjectConfig()
. (See the GitHub Gist for a diff view.)
Approach 1: Returned config
{
"rules": { /* ... */ },
"overrides": [
{
"files": [
"tests/**/*-test.{js,ts}"
],
"rules": {
"prettier": {
"config": false,
"severity": 0
}
}
}
],
"ignore": [],
"format": {},
"plugins": {
"ember-template-lint-plugin-prettier": { /* ... */ }
},
"loadedRules": {},
"loadedConfigurations": {
"4-x-recommended": { /* ... */ },
"a11y": { /* ... */ },
"recommended": { /* ... */ },
"stylistic": { /* ... */ },
"ember-template-lint-plugin-prettier:recommended": { /* ... */ }
},
"_processed": true
}
Approach 2: Returned config
{
"rules": { /* ... */ },
"overrides": [],
"ignore": [],
"format": {},
"plugins": {
"my-shared-plugin": { /* ... */ },
"ember-template-lint-plugin-prettier": { /* ... */ }
},
"loadedRules": {},
"loadedConfigurations": {
"4-x-recommended": { /* ... */ },
"a11y": { /* ... */ },
"recommended": { /* ... */ },
"stylistic": { /* ... */ },
"my-shared-plugin:recommended": { /* ... */ },
"ember-template-lint-plugin-prettier:recommended": { /* ... */ }
},
"_processed": true
}
Notice that, in Approach 2, config.overrides
is equal to the empty array. In other words, validateOverrides()
must have determined that there are no rules to override. This is possibly because, when we enter the function validateOverrides()
, config.overrides
was []
to begin with; if so, the map
function (line 347) would be a no-op.
I didn't find unit tests that cover these questions:
- What is the final value of
config
when a plugin specifiesoverrides
? - What is the final value of
config
when a plugin specifiesoverrides
and the end-developer specifiesoverrides
?
Possible solutions?
I'd expect that:
- A plugin can specify
overrides
, to override the rules that the plugin consumed. - If both the plugin and the end-developer specify
overrides
, the rules from the end-developer'soverrides
win.
Regardless of whether we allow a plugin to specify overrides
, I'd like to suggest that we:
- Write unit tests that cover the two questions above.
- Clarify in
README
which keys a plugin can specify. (The sample plugin,ember-template-lint-plugin-peopleconnect
, represents only one example and may not document everything.)
Related links
I wrote this issue based on a couple of Discord chats. Here are the links to the main messages:
Turns out this happens everywhere where there is hbs
used, as for example in this story:
export const Default = (args: { hello: string; to: string }) => ({
template: hbs`
<Greeting @hello={{this.hello}} @to={{this.to}} />
`,
context: args
});
As this is a .ts
file and I configured vscode to use eslint
as default formatter - my IDE shows this as totally fine, but CLI will complain about it. Meaning: no immediate feedback during development - needs a CI roundtrip for that.
In my case, I have a plugin that defines custom rules and is used in several apps in the yarn workspace. After upgrading to template lint v5 I want to disable a few rules in test files. Using overrides works in each app's config but adding overrides to a shared plugin doesn't work. So, I have to duplicate the overrides in all the apps.