Skip to content

Commit

Permalink
Add overrides option to config (#5521)
Browse files Browse the repository at this point in the history
  • Loading branch information
hudochenkov committed Sep 13, 2021
1 parent cad503b commit 725edf5
Show file tree
Hide file tree
Showing 20 changed files with 755 additions and 39 deletions.
32 changes: 32 additions & 0 deletions docs/user-guide/configure.md
Expand Up @@ -418,3 +418,35 @@ If the globs are absolute paths, they are used as is. If they are relative, they
The `ignoreFiles` property is stripped from extended configs: only the root-level config can ignore files.

_Note that this is not an efficient method for ignoring lots of files._ If you want to ignore a lot of files efficiently, use [`.stylelintignore`](ignore-code.md) or adjust your files globs.

## `overrides`

You can provide configurations under the `overrides` key that will only apply to files that match specific glob patterns, using the same format you would pass on the command line (e.g., `app/**/*.test.css`).

It is possible to override settings based on file glob patterns in your configuration by using the `overrides` key. An example of using the `overrides` key is as follows:

In your `.stylelintrc.json`:

```json
{
"rules": {
"string-quotes": "double"
},

"overrides": [
{
"files": ["components/**/*.css", "pages/**/*.css"],
"rules": {
"string-quotes": "single"
}
}
]
}
```

Here is how overrides work in a configuration file:

- The patterns are applied against the file path relative to the directory of the config file. For example, if your config file has the path `/Users/person/workspace/any-project/.stylelintrc.js` and the file you want to lint has the path `/Users/person/workspace/any-project/components/card.css`, then the pattern provided in `.stylelintrc.js` will be executed against the relative path `components/card.css`.
- 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.
303 changes: 303 additions & 0 deletions lib/__tests__/applyOverrides.test.js
@@ -0,0 +1,303 @@
'use strict';

const path = require('path');
const { applyOverrides } = require('../augmentConfig');

test('no overrides', () => {
const config = {
rules: {
'block-no-empty': true,
},
};

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

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

describe('single matching override', () => {
test('simple override', () => {
const config = {
rules: {
'block-no-empty': true,
},
overrides: [
{
files: ['*.module.css'],
rules: {
'color-no-hex': true,
},
},
],
};

const expectedConfig = {
rules: {
'block-no-empty': true,
'color-no-hex': true,
},
};

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

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

test('simple override, files is a string', () => {
const config = {
rules: {
'block-no-empty': true,
},
overrides: [
{
files: '*.module.css',
rules: {
'color-no-hex': true,
},
},
],
};

const expectedConfig = {
rules: {
'block-no-empty': true,
'color-no-hex': true,
},
};

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

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

test('with plugins', () => {
const config = {
plugins: ['stylelint-plugin'],
rules: {
'block-no-empty': true,
},
overrides: [
{
files: ['*.module.css'],
plugins: ['stylelint-plugin2'],
rules: {
'color-no-hex': true,
},
},
],
};

const expectedConfig = {
plugins: ['stylelint-plugin', 'stylelint-plugin2'],
rules: {
'block-no-empty': true,
'color-no-hex': true,
},
};

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

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

describe('two matching overrides', () => {
test('simple override', () => {
const config = {
rules: {
'block-no-empty': true,
'unit-disallowed-list': ['px'],
},
overrides: [
{
files: ['*.module.css'],
rules: {
'color-no-hex': true,
},
},
{
files: ['*.css'],
rules: {
'block-no-empty': null,
},
},
],
};

const expectedConfig = {
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);
});

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

const expectedConfig = {
plugins: ['stylelint-plugin', 'stylelint-plugin2', 'stylelint-plugin3'],
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', () => {
test('simple override', () => {
const config = {
rules: {
'block-no-empty': true,
},
overrides: [
{
files: ['*.no-module.css'],
rules: {
'color-no-hex': true,
},
},
],
};

const expectedConfig = {
rules: {
'block-no-empty': true,
},
};

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

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

test('with plugins', () => {
const config = {
plugins: ['stylelint-plugin'],
rules: {
'block-no-empty': true,
},
overrides: [
{
files: ['*.no-module.css'],
plugins: ['stylelint-plugin2'],
rules: {
'color-no-hex': true,
},
},
],
};

const expectedConfig = {
plugins: ['stylelint-plugin'],
rules: {
'block-no-empty': true,
},
};

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

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

test('overrides is not an array', () => {
const config = {
rules: {
'block-no-empty': true,
},
overrides: {
files: ['*.module.css'],
rules: {
'color-no-hex': true,
},
},
};

expect(() => {
applyOverrides(config, __dirname, path.join(__dirname, 'style.module.css'));
}).toThrowErrorMatchingInlineSnapshot(
`"The \`overrides\` configuration property should be an array, e.g. { \\"overrides\\": [{ \\"files\\": \\"*.css\\", \\"rules\\": {} }] }."`,
);
});

test('`files` is missing', () => {
const config = {
rules: {
'block-no-empty': true,
},
overrides: [
{
rules: {
'color-no-hex': true,
},
},
],
};

expect(() => {
applyOverrides(config, __dirname, path.join(__dirname, 'style.module.css'));
}).toThrowErrorMatchingInlineSnapshot(
`"Every object in the \`overrides\` configuration property should have a \`files\` property with globs, e.g. { \\"overrides\\": [{ \\"files\\": \\"*.css\\", \\"rules\\": {} }] }."`,
);
});

test('if glob is absolute path', () => {
const config = {
rules: {
'block-no-empty': true,
},
overrides: [
{
files: [path.join(__dirname, 'style.css')],
rules: {
'color-no-hex': true,
},
},
],
};

const expectedConfig = {
rules: {
'block-no-empty': true,
'color-no-hex': true,
},
};

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

expect(applied).toEqual(expectedConfig);
});
@@ -0,0 +1,15 @@
{
"extends": "./plugin-and-one-rule.json",
"plugins": ["../plugin-warn-about-bar"],
"rules": {
"plugin/warn-about-bar": "always"
},
"overrides": [
{
"files": ["*.css"],
"rules": {
"block-no-empty": true
}
}
]
}
14 changes: 14 additions & 0 deletions lib/__tests__/fixtures/config-overrides/extending-simple-rule.json
@@ -0,0 +1,14 @@
{
"extends": "./simple-rule",
"rules": {
"block-no-empty": true
},
"overrides": [
{
"files": ["*.css"],
"rules": {
"color-named": "never"
}
}
]
}
14 changes: 14 additions & 0 deletions lib/__tests__/fixtures/config-overrides/plugin-and-one-rule.json
@@ -0,0 +1,14 @@
{
"plugins": ["../plugin-warn-about-foo"],
"rules": {
"plugin/warn-about-foo": "always"
},
"overrides": [
{
"files": ["*.css"],
"rules": {
"color-named": "never"
}
}
]
}
5 changes: 5 additions & 0 deletions lib/__tests__/fixtures/config-overrides/simple-rule.json
@@ -0,0 +1,5 @@
{
"rules": {
"color-named": "always-where-possible"
}
}
5 changes: 5 additions & 0 deletions lib/__tests__/fixtures/config-overrides/style.css
@@ -0,0 +1,5 @@
.foo {
color: pink;
}

.bar {}

0 comments on commit 725edf5

Please sign in to comment.