From aaa9a0fd96ba96238c49510e02fcbbc94395c02a Mon Sep 17 00:00:00 2001 From: jeddy3 Date: Mon, 25 Apr 2016 15:23:13 +0100 Subject: [PATCH] Add isStandardSelector and reduce scope of isStandardRule --- src/rules/selector-class-pattern/index.js | 10 +++++++--- src/rules/selector-id-pattern/index.js | 10 +++++++--- src/rules/selector-max-specificity/index.js | 2 ++ src/rules/selector-no-attribute/index.js | 5 ++++- src/rules/selector-no-combinator/index.js | 5 ++++- src/rules/selector-no-id/index.js | 7 +++++-- src/rules/selector-no-type/index.js | 5 ++++- src/rules/selector-no-universal/index.js | 5 ++++- src/rules/selector-no-vendor-prefix/index.js | 5 ++++- src/rules/selector-type-case/index.js | 5 ++++- src/utils/__tests__/isStandardRule-test.js | 16 +--------------- .../__tests__/isStandardSelector-test.js | 19 +++++++++++++++++++ src/utils/index.js | 1 + src/utils/isStandardRule.js | 3 --- src/utils/isStandardSelector.js | 13 +++++++++++++ 15 files changed, 79 insertions(+), 32 deletions(-) create mode 100644 src/utils/__tests__/isStandardSelector-test.js create mode 100644 src/utils/isStandardSelector.js diff --git a/src/rules/selector-class-pattern/index.js b/src/rules/selector-class-pattern/index.js index 003d9383b1..125fb5d58c 100644 --- a/src/rules/selector-class-pattern/index.js +++ b/src/rules/selector-class-pattern/index.js @@ -3,6 +3,7 @@ import selectorParser from "postcss-selector-parser" import _ from "lodash" import { isStandardRule, + isStandardSelector, report, ruleMessages, validateOptions, @@ -36,13 +37,16 @@ export default function (pattern, options) { root.walkRules(rule => { if (!isStandardRule(rule)) { return } + const { selector } = rule + if (!isStandardSelector(selector)) { return } + // Only bother resolving selectors that have an interpolating & - if (shouldResolveNestedSelectors && hasInterpolatingAmpersand(rule.selector)) { - resolveNestedSelector(rule.selector, rule).forEach(selector => { + if (shouldResolveNestedSelectors && hasInterpolatingAmpersand(selector)) { + resolveNestedSelector(selector, rule).forEach(selector => { selectorParser(s => checkSelector(s, rule)).process(selector) }) } else { - selectorParser(s => checkSelector(s, rule)).process(rule.selector) + selectorParser(s => checkSelector(s, rule)).process(selector) } }) diff --git a/src/rules/selector-id-pattern/index.js b/src/rules/selector-id-pattern/index.js index 258f81c530..03e9c6c97b 100644 --- a/src/rules/selector-id-pattern/index.js +++ b/src/rules/selector-id-pattern/index.js @@ -2,6 +2,7 @@ import selectorParser from "postcss-selector-parser" import { isRegExp, isString } from "lodash" import { isStandardRule, + isStandardSelector, report, ruleMessages, validateOptions, @@ -25,8 +26,11 @@ export default function (pattern) { root.walkRules(rule => { if (!isStandardRule(rule)) { return } - - selectorParser(checkSelector).process(rule.selector) + + const { selector } = rule + if (!isStandardSelector(selector)) { return } + + selectorParser(checkSelector).process(selector) function checkSelector(fullSelector) { fullSelector.eachInside(selectorNode => { @@ -34,7 +38,7 @@ export default function (pattern) { const { value, sourceIndex } = selectorNode if (normalizedPattern.test(value)) { return } - + report({ result, ruleName, diff --git a/src/rules/selector-max-specificity/index.js b/src/rules/selector-max-specificity/index.js index 20753dc50c..f2efa45b89 100755 --- a/src/rules/selector-max-specificity/index.js +++ b/src/rules/selector-max-specificity/index.js @@ -3,6 +3,7 @@ import resolvedNestedSelector from "postcss-resolve-nested-selector" import { isStandardRule, + isStandardSelector, report, ruleMessages, validateOptions, @@ -28,6 +29,7 @@ export default function (max) { root.walkRules(rule => { if (!isStandardRule(rule)) { return } + if (!isStandardSelector(rule.selector)) { return } // Using rule.selectors gets us each selector in the eventuality we have a comma separated set rule.selectors.forEach(selector => { resolvedNestedSelector(selector, rule).forEach(resolvedSelector => { diff --git a/src/rules/selector-no-attribute/index.js b/src/rules/selector-no-attribute/index.js index 57d7dff42c..deaa81efe1 100644 --- a/src/rules/selector-no-attribute/index.js +++ b/src/rules/selector-no-attribute/index.js @@ -1,6 +1,7 @@ import selectorParser from "postcss-selector-parser" import { isStandardRule, + isStandardSelector, report, ruleMessages, validateOptions, @@ -19,6 +20,8 @@ export default function (actual) { root.walkRules(rule => { if (!isStandardRule(rule)) { return } + const { selector } = rule + if (!isStandardSelector(selector)) { return } selectorParser(selectorAST => { selectorAST.eachAttribute(attribute => { report({ @@ -30,7 +33,7 @@ export default function (actual) { }) }) }) - .process(rule.selector) + .process(selector) }) } } diff --git a/src/rules/selector-no-combinator/index.js b/src/rules/selector-no-combinator/index.js index 2c381c0e1e..0db9b69be7 100644 --- a/src/rules/selector-no-combinator/index.js +++ b/src/rules/selector-no-combinator/index.js @@ -1,6 +1,7 @@ import selectorParser from "postcss-selector-parser" import { isStandardRule, + isStandardSelector, report, ruleMessages, validateOptions, @@ -19,6 +20,8 @@ export default function (actual) { root.walkRules(rule => { if (!isStandardRule(rule)) { return } + const { selector } = rule + if (!isStandardSelector(selector)) { return } selectorParser(selectorAST => { selectorAST.eachCombinator(combinator => { report({ @@ -30,7 +33,7 @@ export default function (actual) { }) }) }) - .process(rule.selector) + .process(selector) }) } } diff --git a/src/rules/selector-no-id/index.js b/src/rules/selector-no-id/index.js index b34b4ddc98..d305811247 100644 --- a/src/rules/selector-no-id/index.js +++ b/src/rules/selector-no-id/index.js @@ -1,7 +1,8 @@ import selectorParser from "postcss-selector-parser" import { - isStandardRule, isKeyframeRule, + isStandardRule, + isStandardSelector, report, ruleMessages, validateOptions, @@ -21,6 +22,8 @@ export default function (actual) { root.walkRules(rule => { if (!isStandardRule(rule)) { return } if (isKeyframeRule(rule)) { return } + const { selector } = rule + if (!isStandardSelector(selector)) { return } selectorParser(selectorAST => { selectorAST.eachId(idNode => { @@ -35,7 +38,7 @@ export default function (actual) { }) }) }) - .process(rule.selector) + .process(selector) }) } } diff --git a/src/rules/selector-no-type/index.js b/src/rules/selector-no-type/index.js index cb513ef94c..bf504a6871 100644 --- a/src/rules/selector-no-type/index.js +++ b/src/rules/selector-no-type/index.js @@ -3,6 +3,7 @@ import { get } from "lodash" import { isKeyframeRule, isStandardRule, + isStandardSelector, isStandardTypeSelector, optionsHaveIgnored, report, @@ -31,8 +32,10 @@ export default function (on, options) { if (!isStandardRule(rule)) { return } if (isKeyframeRule(rule)) { return } + const { selector } = rule + if (!isStandardSelector(selector)) { return } - selectorParser(checkSelector).process(rule.selector) + selectorParser(checkSelector).process(selector) function checkSelector(selectorAST) { selectorAST.eachTag(tag => { diff --git a/src/rules/selector-no-universal/index.js b/src/rules/selector-no-universal/index.js index 352b0a5af5..81c1fd69e8 100644 --- a/src/rules/selector-no-universal/index.js +++ b/src/rules/selector-no-universal/index.js @@ -1,6 +1,7 @@ import selectorParser from "postcss-selector-parser" import { isStandardRule, + isStandardSelector, report, ruleMessages, validateOptions, @@ -19,6 +20,8 @@ export default function (actual) { root.walkRules(rule => { if (!isStandardRule(rule)) { return } + const { selector } = rule + if (!isStandardSelector(selector)) { return } selectorParser(selectorAST => { selectorAST.eachUniversal(universal => { report({ @@ -30,7 +33,7 @@ export default function (actual) { }) }) }) - .process(rule.selector) + .process(selector) }) } } diff --git a/src/rules/selector-no-vendor-prefix/index.js b/src/rules/selector-no-vendor-prefix/index.js index a6361c30d7..14e07d55ee 100644 --- a/src/rules/selector-no-vendor-prefix/index.js +++ b/src/rules/selector-no-vendor-prefix/index.js @@ -1,6 +1,7 @@ import selectorParser from "postcss-selector-parser" import { isStandardRule, + isStandardSelector, report, ruleMessages, isAutoprefixable, @@ -20,6 +21,8 @@ export default function (actual) { root.walkRules(rule => { if (!isStandardRule(rule)) { return } + const { selector } = rule + if (!isStandardSelector(selector)) { return } selectorParser(selectorTree => { selectorTree.eachPseudo(pseudoNode => { if (isAutoprefixable.selector(pseudoNode.value)) { @@ -32,7 +35,7 @@ export default function (actual) { }) } }) - }).process(rule.selector) + }).process(selector) }) } } diff --git a/src/rules/selector-type-case/index.js b/src/rules/selector-type-case/index.js index b1456c4880..84096a55a3 100644 --- a/src/rules/selector-type-case/index.js +++ b/src/rules/selector-type-case/index.js @@ -2,6 +2,7 @@ import selectorParser from "postcss-selector-parser" import { isKeyframeRule, isStandardRule, + isStandardSelector, isStandardTypeSelector, report, ruleMessages, @@ -29,6 +30,8 @@ export default function (expectation) { if (!isStandardRule(rule)) { return } if (isKeyframeRule(rule)) { return } + const { selector } = rule + if (!isStandardSelector(selector)) { return } function checkSelector(selectorAST) { selectorAST.eachTag(tag => { @@ -50,7 +53,7 @@ export default function (expectation) { }) } - selectorParser(checkSelector).process(rule.selector) + selectorParser(checkSelector).process(selector) }) } } diff --git a/src/utils/__tests__/isStandardRule-test.js b/src/utils/__tests__/isStandardRule-test.js index 4edb075528..a3ef83bb71 100644 --- a/src/utils/__tests__/isStandardRule-test.js +++ b/src/utils/__tests__/isStandardRule-test.js @@ -1,11 +1,10 @@ import isStandardRule from "../isStandardRule" import less from "postcss-less" -import scss from "postcss-scss" import postcss from "postcss" import test from "tape" test("isStandardRule", t => { - t.plan(16) + t.plan(15) rules("a {}", rule => { t.ok(isStandardRule(rule), "type") @@ -30,10 +29,6 @@ test("isStandardRule", t => { t.notOk(isStandardRule(rule), "custom-property-set") }) - scssRules(".n-#{$n}", rule => { - t.notOk(isStandardRule(rule), "scss interpolation") - }) - lessRules(".mixin-name(@var);", rule => { t.notOk(isStandardRule(rule), "called Less class parametric mixin") }) @@ -58,9 +53,6 @@ test("isStandardRule", t => { lessRules("#namespace.mixin-name;", rule => { t.notOk(isStandardRule(rule), "called namespaced Less mixin (compound)") }) - lessRules(".n-@{n}", rule => { - t.notOk(isStandardRule(rule), "Less interpolation") - }) }) function rules(css, cb) { @@ -74,9 +66,3 @@ function lessRules(css, cb) { result.root.walkRules(cb) }) } - -function scssRules(css, cb) { - postcss().process(css, { syntax: scss }).then(result => { - result.root.walkRules(cb) - }) -} diff --git a/src/utils/__tests__/isStandardSelector-test.js b/src/utils/__tests__/isStandardSelector-test.js new file mode 100644 index 0000000000..a4cbe927d8 --- /dev/null +++ b/src/utils/__tests__/isStandardSelector-test.js @@ -0,0 +1,19 @@ +import test from "tape" +import isStandardSelector from "../isStandardSelector" + +test("isStandardSelector", t => { + t.ok(isStandardSelector("a"), "type") + t.ok(isStandardSelector(".a"), "class") + t.ok(isStandardSelector("[a=a]"), "attribute") + t.ok(isStandardSelector("*"), "universal") + t.ok(isStandardSelector("a:last-child"), "pseudo-class") + t.ok(isStandardSelector("a:not(.b)"), "pseudo-class with function") + t.ok(isStandardSelector("a::after"), "pseudo-element") + t.ok(isStandardSelector("a.b"), "compound") + t.ok(isStandardSelector("a > b"), "complex") + t.ok(isStandardSelector("a, b"), "list") + t.notOk(isStandardSelector("#{50% - $n}"), "SCSS interpolation (id)") + t.notOk(isStandardSelector(".n-#{$n}"), "SCSS interpolation (class)") + t.notOk(isStandardSelector(".n-@{n}"), "Less interpolation") + t.end() +}) diff --git a/src/utils/index.js b/src/utils/index.js index 4367859459..c4cf9f49b6 100644 --- a/src/utils/index.js +++ b/src/utils/index.js @@ -18,6 +18,7 @@ export { default as isSingleLineString } from "./isSingleLineString" export { default as isStandardDeclaration } from "./isStandardDeclaration" export { default as isStandardFunction } from "./isStandardFunction" export { default as isStandardRule } from "./isStandardRule" +export { default as isStandardSelector } from "./isStandardSelector" export { default as isStandardTypeSelector } from "./isStandardTypeSelector" export { default as isStandardValue } from "./isStandardValue" export { default as isValidHex } from "./isValidHex" diff --git a/src/utils/isStandardRule.js b/src/utils/isStandardRule.js index bb7380ff9f..ca2be40392 100644 --- a/src/utils/isStandardRule.js +++ b/src/utils/isStandardRule.js @@ -14,9 +14,6 @@ export default function (rule) { // Custom property set (e.g. --custom-property-set: {}) if (_.endsWith(selector, ":")) { return false } - // SCSS or Less interpolation - if (/#{.+?}|@{.+?}|\$\(.+?\)/.test(selector)) { return false } - // Called Less mixin (e.g. a { .mixin() }) if (rule.ruleWithoutBody) { return false } diff --git a/src/utils/isStandardSelector.js b/src/utils/isStandardSelector.js new file mode 100644 index 0000000000..cabc7f7234 --- /dev/null +++ b/src/utils/isStandardSelector.js @@ -0,0 +1,13 @@ +/** + * Check whether a selector is standard + * + * @param {string} selector + * @return {boolean} If `true`, the selector is standard + */ +export default function (selector) { + + // SCSS or Less interpolation + if (/#{.+?}|@{.+?}|\$\(.+?\)/.test(selector)) { return false } + + return true +}