From 5d2a8cab75b4bcf0b81f4f81686ead04d3ef79a6 Mon Sep 17 00:00:00 2001 From: Pieter <4687577+pajter@users.noreply.github.com> Date: Sat, 30 May 2020 13:08:24 +0200 Subject: [PATCH] Add optional name to extended rule object (#119) --- CHANGELOG.md | 1 + rules/order/README.md | 1 + rules/order/getDescription.js | 5 +- rules/order/tests/index.js | 77 +++++++++++++++++++++++++++ rules/order/tests/validate-options.js | 59 ++++++++++++++++++++ rules/order/validatePrimaryOption.js | 4 ++ 6 files changed, 146 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1414256..7f5b5fb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). ## Head * Fixed `order` not reporting warnings, if autofix didn't fix them. +* Added `name` option to extended rule object to improve error messaging. ## 4.0.0 diff --git a/rules/order/README.md b/rules/order/README.md index 641a88a..25d4a6e 100644 --- a/rules/order/README.md +++ b/rules/order/README.md @@ -131,6 +131,7 @@ Object parameters: * `selector`: `string`|`regex`. Selector pattern. A string will be translated into a RegExp — `new RegExp(yourString)` — so _be sure to escape properly_. Examples: * `selector: /^&:[\w-]+$/` matches simple pseudo-classes. E. g., `&:hover`, `&:first-child`. Doesn't match complex pseudo-classes, e. g. `&:not(.is-visible)`. * `selector: /^&::[\w-]+$/` matches pseudo-elements. E. g. `&::before`, `&::placeholder`. +* `name`: `string`. Selector name (optional). Will be used in error output to help identify extended rule object. Matches all rules: diff --git a/rules/order/getDescription.js b/rules/order/getDescription.js index 2ca0478..dbb90a4 100644 --- a/rules/order/getDescription.js +++ b/rules/order/getDescription.js @@ -35,7 +35,10 @@ module.exports = function getDescription(item) { if (item.type === 'rule') { text = 'rule'; - if (item.selector) { + if (item.name) { + // Prefer 'name' property for better error messaging + text += ` "${item.name}"`; + } else if (item.selector) { text += ` with selector matching "${item.selector}"`; } } diff --git a/rules/order/tests/index.js b/rules/order/tests/index.js index a6d8bbd..ff1c547 100644 --- a/rules/order/tests/index.js +++ b/rules/order/tests/index.js @@ -1070,6 +1070,83 @@ testRule({ ], }); +testRule({ + ruleName, + config: [ + [ + { + type: 'rule', + }, + { + type: 'rule', + selector: /^&:\w/, + name: 'State', + }, + { + type: 'rule', + selector: /^&/, + name: 'Child', + }, + ], + ], + fix: true, + + accept: [ + { + code: ` + a { + b & {} + &:hover {} + & b {} + } + `, + }, + { + code: ` + a { + b & {} + & b {} + } + `, + }, + ], + + reject: [ + { + code: ` + a { + b & {} + & b {} + &:hover {} + } + `, + fixed: ` + a { + b & {} + &:hover {} + & b {} + } + `, + message: messages.expected('rule "State"', 'rule "Child"'), + }, + { + code: ` + a { + &:hover {} + b & {} + } + `, + fixed: ` + a { + b & {} + &:hover {} + } + `, + message: messages.expected('rule', 'rule "State"'), + }, + ], +}); + testRule({ ruleName, syntax: 'less', diff --git a/rules/order/tests/validate-options.js b/rules/order/tests/validate-options.js index 4822a3c..1362bd9 100644 --- a/rules/order/tests/validate-options.js +++ b/rules/order/tests/validate-options.js @@ -56,6 +56,11 @@ testConfig({ type: 'rule', selector: '^&:\\w', }, + { + type: 'rule', + selector: /^&::\w/, + name: 'Pseudo', + }, { type: 'rule', }, @@ -264,6 +269,60 @@ testConfig({ message: `Invalid option "[{"type":"rule","selector":null}]" for rule ${ruleName}`, }); +testConfig({ + ruleName, + description: 'invalid. name is empty', + valid: false, + config: [ + { + type: 'rule', + name: '', + }, + ], + message: `Invalid option "[{"type":"rule","name":""}]" for rule ${ruleName}`, +}); + +testConfig({ + ruleName, + description: 'invalid. name is not a string', + valid: false, + config: [ + { + type: 'rule', + name: null, + }, + ], + message: `Invalid option "[{"type":"rule","name":null}]" for rule ${ruleName}`, +}); + +testConfig({ + ruleName, + description: 'invalid. selector is valid, but name is invalid', + valid: false, + config: [ + { + type: 'rule', + selector: '^&:hover', + name: null, + }, + ], + message: `Invalid option "[{"type":"rule","selector":"^&:hover","name":null}]" for rule ${ruleName}`, +}); + +testConfig({ + ruleName, + description: 'invalid. name is valid, but select is invalid', + valid: false, + config: [ + { + type: 'rule', + selector: null, + name: 'Element', + }, + ], + message: `Invalid option "[{"type":"rule","selector":null,"name":"Element"}]" for rule ${ruleName}`, +}); + testConfig({ ruleName, description: 'disableFix true', diff --git a/rules/order/validatePrimaryOption.js b/rules/order/validatePrimaryOption.js index b47330f..c895cdf 100644 --- a/rules/order/validatePrimaryOption.js +++ b/rules/order/validatePrimaryOption.js @@ -65,6 +65,10 @@ module.exports = function validatePrimaryOption(actualOptions) { (_.isString(item.selector) && item.selector.length) || _.isRegExp(item.selector); } + + if (result && !_.isUndefined(item.name)) { + result = _.isString(item.name) && item.name.length; + } } return result;