From c088c39a31d2bfd2332de14a09076fcd5d4ec370 Mon Sep 17 00:00:00 2001 From: francoismassart Date: Wed, 19 May 2021 16:21:27 +0200 Subject: [PATCH] feat: shared settings --- README.md | 39 +++++++++++++++++++++--- docs/rules/classnames-order.md | 2 +- docs/rules/no-contradicting-classname.md | 2 +- docs/rules/no-custom-classname.md | 8 +++-- lib/rules/classnames-order.js | 13 ++++---- lib/rules/no-contradicting-classname.js | 7 ++--- lib/rules/no-custom-classname.js | 8 ++--- lib/util/settings.js | 31 +++++++++++++++++++ tests/lib/rules/classnames-order.js | 21 +++++++++++++ 9 files changed, 108 insertions(+), 23 deletions(-) create mode 100644 lib/util/settings.js diff --git a/README.md b/README.md index abc3235..e7fc224 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/docs/rules/classnames-order.md b/docs/rules/classnames-order.md index 5406f5d..7b7baf8 100644 --- a/docs/rules/classnames-order.md +++ b/docs/rules/classnames-order.md @@ -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. diff --git a/docs/rules/no-contradicting-classname.md b/docs/rules/no-contradicting-classname.md index 7920793..169bb81 100644 --- a/docs/rules/no-contradicting-classname.md +++ b/docs/rules/no-contradicting-classname.md @@ -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. diff --git a/docs/rules/no-custom-classname.md b/docs/rules/no-custom-classname.md index 61e48ea..eed14a6 100644 --- a/docs/rules/no-custom-classname.md +++ b/docs/rules/no-custom-classname.md @@ -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. @@ -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 diff --git a/lib/rules/classnames-order.js b/lib/rules/classnames-order.js index 883d934..c92a3ee 100644 --- a/lib/rules/classnames-order.js +++ b/lib/rules/classnames-order.js @@ -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 @@ -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); diff --git a/lib/rules/no-contradicting-classname.js b/lib/rules/no-contradicting-classname.js index b268121..a39bea1 100644 --- a/lib/rules/no-contradicting-classname.js +++ b/lib/rules/no-contradicting-classname.js @@ -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 @@ -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); diff --git a/lib/rules/no-custom-classname.js b/lib/rules/no-custom-classname.js index 94d2615..513f8cc 100644 --- a/lib/rules/no-custom-classname.js +++ b/lib/rules/no-custom-classname.js @@ -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 @@ -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); diff --git a/lib/util/settings.js b/lib/util/settings.js new file mode 100644 index 0000000..a2b426a --- /dev/null +++ b/lib/util/settings.js @@ -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; diff --git a/tests/lib/rules/classnames-order.js b/tests/lib/rules/classnames-order.js index cb99528..8e85217 100644 --- a/tests/lib/rules/classnames-order.js +++ b/tests/lib/rules/classnames-order.js @@ -96,6 +96,27 @@ ruleTester.run("classnames-order", rule, { }, ], }, + { + code: `
Options override shared settings
`, + options: [ + { + config: { prefix: "opts-" }, + }, + ], + settings: { + tailwindcss: { + config: { prefix: "sttgs-" }, + }, + }, + }, + { + code: `
Use settings
`, + settings: { + tailwindcss: { + config: { prefix: "sttgs-", separator: "_" }, + }, + }, + }, ], invalid: [ {