Skip to content

Commit

Permalink
feat: shared settings
Browse files Browse the repository at this point in the history
  • Loading branch information
francoismassart committed May 19, 2021
1 parent 808ea2e commit c088c39
Show file tree
Hide file tree
Showing 9 changed files with 108 additions and 23 deletions.
39 changes: 35 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,52 @@ Configure the rules you want to use under the rules section.
```json
{
"rules": {
"tailwindcss/classnames-order": 2,
"tailwindcss/no-custom-classname": 2,
"tailwindcss/no-contradicting-classname": 2
"tailwindcss/classnames-order": "warn",
"tailwindcss/no-custom-classname": "warn",
"tailwindcss/no-contradicting-classname": "error"
}
}
```

Learn more about [Configuring Rules in ESLint](https://eslint.org/docs/user-guide/configuring/rules).

## Optional shared settings

Most rules shares the same settings, instead of duplicating some options...

You should also specify settings that will be shared across all the plugin rules.
[More about eslint shared settings](https://eslint.org/docs/user-guide/configuring#adding-shared-settings).

All these settings have nice default values that are explained in each rules' documentation. I'm listing them in the code below just to show them.

```json
{
"settings": {
"tailwindcss": {
// These are the default values but feel free to customize
"callees": ["classnames", "clsx", "ctl"],
"config": "tailwind.config.js",
"groups": defaultGroups, // imported from groups.js
"prependCustom": false,
"removeDuplicates": true,
"whitelist": []
}
}
}
```

The plugin will look for each setting value in this order and stop looking as soon as it finds the settings:

1. In the rule option argument (rule level)
2. In the shared settings (plugin level)
3. Default value of the requested setting (plugin level)...

## Supported Rules

Learn more about each supported rules by reading their documentation:

- [`classnames-order`](docs/rules/classnames-order.md): order classnames by target properties then by variants (`[size:][theme:][state:]`)
- [`no-custom-classname`](docs/rules/no-custom-classname.md): only allow classnames from Tailwind CSS
- [`no-custom-classname`](docs/rules/no-custom-classname.md): only allow classnames from Tailwind CSS and the values from the `whitelist` option
- [`no-contradicting-classname`](docs/rules/no-contradicting-classname.md): e.g. avoid `p-2 p-3`, different Tailwind CSS classnames (`pt-2` & `pt-3`) but targeting the same property several times for the same variant.

## Upcoming Rules
Expand Down
2 changes: 1 addition & 1 deletion docs/rules/classnames-order.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Examples of **correct** code for this rule:
...
```

### `callees` (default: `["ctl"]`)
### `callees` (default: `["classnames", "clsx", "ctl"]`)

If you use some utility library like [@netlify/classnames-template-literals](https://github.com/netlify/classnames-template-literals), you can add its name to the list to make sure it gets parsed by this rule.

Expand Down
2 changes: 1 addition & 1 deletion docs/rules/no-contradicting-classname.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Examples of **correct** code for this rule:
...
```

### `callees` (default: `["ctl"]`)
### `callees` (default: `["classnames", "clsx", "ctl"]`)

If you use some utility library like [@netlify/classnames-template-literals](https://github.com/netlify/classnames-template-literals), you can add its name to the list to make sure it gets parsed by this rule.

Expand Down
8 changes: 6 additions & 2 deletions docs/rules/no-custom-classname.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Examples of **correct** code for this rule:
...
```

### `callees` (default: `["ctl"]`)
### `callees` (default: `["classnames", "clsx", "ctl"]`)

If you use some utility library like [@netlify/classnames-template-literals](https://github.com/netlify/classnames-template-literals), you can add its name to the list to make sure it gets parsed by this rule.

Expand All @@ -56,7 +56,11 @@ The `whitelist` is empty by default but you can add custom regular expressions t

For example, imagine we are using the following custom classnames: `skin-summer`, `skin-xmas`, `custom-1`, `custom-2`, `custom-3`.

The `whitelist` options should be set to `['skin\-(summer|xmas)', 'custom\-[1-3]']`
The `whitelist` options should be set to:

- `['skin\\-(summer|xmas)', 'custom\\-[1-3]']`
- or if you don't like regular expressions (but you should):
`['skin\\-summer', 'skin\\-xmas', 'custom\\-1', 'custom\\-2', 'custom\\-3']`

## Further Reading

Expand Down
13 changes: 6 additions & 7 deletions lib/rules/classnames-order.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
'use strict';

const docsUrl = require('../util/docsUrl');
const defaultGroups = require('../config/groups').groups;
const customConfig = require('../util/customConfig');
const astUtil = require('../util/ast');
const attrUtil = require('../util/attr');
const groupUtil = require('../util/groupMethods');
const removeDuplicatesFromArray = require('../util/removeDuplicatesFromArray');
const getOption = require('../util/settings');

//------------------------------------------------------------------------------
// Rule Definition
Expand Down Expand Up @@ -63,12 +63,11 @@ module.exports = {
},

create: function (context) {
const configuration = context.options[0] || {};
const callees = configuration.callees || ['ctl'];
const twConfig = configuration.config || 'tailwind.config.js';
const groupsConfig = configuration.groups || defaultGroups;
const prependCustom = configuration.prependCustom || false;
const removeDuplicates = !(configuration.removeDuplicates === false);
const callees = getOption(context, 'callees');
const twConfig = getOption(context, 'config');
const groupsConfig = getOption(context, 'groups');
const prependCustom = getOption(context, 'prependCustom');
const removeDuplicates = getOption(context, 'removeDuplicates');

const mergedConfig = customConfig.resolve(twConfig);

Expand Down
7 changes: 3 additions & 4 deletions lib/rules/no-contradicting-classname.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const astUtil = require('../util/ast');
const attrUtil = require('../util/attr');
const groupUtil = require('../util/groupMethods');
const removeDuplicatesFromArray = require('../util/removeDuplicatesFromArray');
const resolveConfig = require('tailwindcss/resolveConfig');
const getOption = require('../util/settings');

//------------------------------------------------------------------------------
// Rule Definition
Expand Down Expand Up @@ -52,9 +52,8 @@ module.exports = {
},

create: function (context) {
const configuration = context.options[0] || {};
const callees = configuration.callees || ['ctl'];
const twConfig = configuration.config || 'tailwind.config.js';
const callees = getOption(context, 'callees');
const twConfig = getOption(context, 'config');

const mergedConfig = customConfig.resolve(twConfig);

Expand Down
8 changes: 4 additions & 4 deletions lib/rules/no-custom-classname.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const astUtil = require('../util/ast');
const attrUtil = require('../util/attr');
const groupUtil = require('../util/groupMethods');
const removeDuplicatesFromArray = require('../util/removeDuplicatesFromArray');
const getOption = require('../util/settings');

//------------------------------------------------------------------------------
// Rule Definition
Expand Down Expand Up @@ -56,10 +57,9 @@ module.exports = {
},

create: function (context) {
const configuration = context.options[0] || {};
const callees = configuration.callees || ['ctl'];
const twConfig = configuration.config || 'tailwind.config.js';
const whitelist = configuration.whitelist || [];
const callees = getOption(context, 'callees');
const twConfig = getOption(context, 'config');
const whitelist = getOption(context, 'whitelist');

const mergedConfig = customConfig.resolve(twConfig);

Expand Down
31 changes: 31 additions & 0 deletions lib/util/settings.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict';
const defaultGroups = require('../config/groups').groups;

function getOption(context, name) {
// Options (defined at rule level)
const options = context.options[0] || {};
if (options[name] != undefined) {
return options[name];
}
// Settings (defined at plugin level, shared accross rules)
if (context.settings && context.settings.tailwindcss && context.settings.tailwindcss[name] != undefined) {
return context.settings.tailwindcss[name];
}
// Fallback to defaults
switch (name) {
case 'callees':
return ['classnames', 'clsx', 'ctl'];
case 'config':
return 'tailwind.config.js';
case 'groups':
return defaultGroups;
case 'prependCustom':
return false;
case 'removeDuplicates':
return true;
case 'whitelist':
return [];
}
}

module.exports = getOption;
21 changes: 21 additions & 0 deletions tests/lib/rules/classnames-order.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,27 @@ ruleTester.run("classnames-order", rule, {
},
],
},
{
code: `<div class="opts-w-12 lg:opts-w-6">Options override shared settings</div>`,
options: [
{
config: { prefix: "opts-" },
},
],
settings: {
tailwindcss: {
config: { prefix: "sttgs-" },
},
},
},
{
code: `<div class="sttgs-w-12 lg_sttgs-w-6">Use settings</div>`,
settings: {
tailwindcss: {
config: { prefix: "sttgs-", separator: "_" },
},
},
},
],
invalid: [
{
Expand Down

0 comments on commit c088c39

Please sign in to comment.