Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change extends in overrides to be consistent with plugins behaviour #6380

Merged
merged 14 commits into from Oct 27, 2022
5 changes: 5 additions & 0 deletions .changeset/grumpy-scissors-watch.md
@@ -0,0 +1,5 @@
---
"stylelint": major
---

Change: `extends` in `overrides` to merge to be consistent with `plugins` behaviour
23 changes: 23 additions & 0 deletions docs/migration-guide/to-15.md
@@ -0,0 +1,23 @@
# Migrating to 15.0.0

## Change of `overrides.`extends` behavior
ybiquitous marked this conversation as resolved.
Show resolved Hide resolved

We changed the `overrides.extends` behavior to merge rather than replace, to make it consistent with the `overrides.plugins`.

If you would like to keep the previous behavior, you should change your config to:

```diff json
{
- "extends": ["config-a"]
ybiquitous marked this conversation as resolved.
Show resolved Hide resolved
"overrides": [
{
"rules": ["*.module.css"],
"extends": ["config-b"]
},
+ {
+ "rules": ["*.css"],
+ "extends": ["config-a"]
+ },
jeddy3 marked this conversation as resolved.
Show resolved Hide resolved
]
}
```
2 changes: 2 additions & 0 deletions docs/user-guide/configure.md
Expand Up @@ -297,6 +297,8 @@ Here is how overrides work in a configuration file:
- Glob pattern overrides have higher precedence than the regular configuration in the same config file. Multiple overrides within the same config are applied in order. That is, the last override block in a config file always has the highest precedence.
- A glob specific configuration works almost the same as any other Stylelint config. Override blocks can contain any configuration options that are valid in a regular config.
- Multiple glob patterns can be provided within a single override block. A file must match at least one of the supplied patterns for the configuration to apply.
- `customSyntax` will be replaced by overrides.
- `plugins`, `extends`, `rules`, etc. will be appended.

## `defaultSeverity`

Expand Down
39 changes: 39 additions & 0 deletions lib/__tests__/applyOverrides.test.js
Expand Up @@ -198,6 +198,45 @@ describe('two matching overrides', () => {

expect(applied).toEqual(expectedConfig);
});

test('with extends', () => {
const config = {
extends: ['stylelint-config1'],
rules: {
'block-no-empty': true,
'unit-disallowed-list': ['px'],
},
overrides: [
{
files: ['*.module.css'],
extends: ['stylelint-config2'],
rules: {
'color-no-hex': true,
},
},
{
files: ['*.css'],
extends: ['stylelint-config3'],
rules: {
'block-no-empty': null,
},
},
],
};

const expectedConfig = {
extends: ['stylelint-config1', 'stylelint-config2', 'stylelint-config3'],
rules: {
'block-no-empty': null,
'unit-disallowed-list': ['px'],
'color-no-hex': true,
},
};

const applied = applyOverrides(config, __dirname, path.join(__dirname, 'style.module.css'));

expect(applied).toEqual(expectedConfig);
});
});

describe('no matching overrides', () => {
Expand Down
19 changes: 18 additions & 1 deletion lib/augmentConfig.js
Expand Up @@ -8,6 +8,7 @@ const normalizeAllRuleSettings = require('./normalizeAllRuleSettings');
const normalizePath = require('normalize-path');
const path = require('path');

/** @typedef {import('stylelint').ConfigExtends} StyleLintConfigExtends */
/** @typedef {import('stylelint').ConfigPlugins} StylelintConfigPlugins */
/** @typedef {import('stylelint').ConfigProcessor} StylelintConfigProcessor */
/** @typedef {import('stylelint').ConfigProcessors} StylelintConfigProcessors */
Expand Down Expand Up @@ -234,7 +235,7 @@ function loadExtendedConfig(stylelint, configDir, extendLookup) {

/**
* When merging configs (via extends)
* - plugin and processor arrays are joined
* - plugin, extends, overrides, processor arrays are joined
* - rules are merged via Object.assign, so there is no attempt made to
* merge any given rule's settings. If b contains the same rule as a,
* b's rule settings will override a's rule settings entirely.
Expand Down Expand Up @@ -289,6 +290,21 @@ function mergeConfigs(a, b) {
}
}

/** @type {{extends: StyleLintConfigExtends}} */
const extendsMerger = {};

if (a.extends || b.extends) {
extendsMerger.extends = [];

if (a.extends) {
extendsMerger.extends = extendsMerger.extends.concat(a.extends);
}

if (b.extends) {
extendsMerger.extends = [...new Set(extendsMerger.extends.concat(b.extends))];
}
}

const rulesMerger = {};

if (a.rules || b.rules) {
Expand All @@ -298,6 +314,7 @@ function mergeConfigs(a, b) {
const result = {
...a,
...b,
...extendsMerger,
...processorMerger,
...pluginMerger,
...overridesMerger,
Expand Down