Skip to content

Commit

Permalink
Fix false negatives for CSS-In-JS in color-no-invalid-hex (#3957)
Browse files Browse the repository at this point in the history
  • Loading branch information
fogost authored and jeddy3 committed Feb 21, 2019
1 parent ed3d097 commit ee266b6
Show file tree
Hide file tree
Showing 21 changed files with 116 additions and 111 deletions.
1 change: 0 additions & 1 deletion lib/rules/at-rule-no-unknown/__tests__/index.js
Expand Up @@ -160,7 +160,6 @@ testRule(rule, {
]
});


testRule(rule, {
ruleName,
config: [true, { ignoreAtRules: [/^my-/] }],
Expand Down
21 changes: 21 additions & 0 deletions lib/rules/color-no-invalid-hex/__tests__/index.js
Expand Up @@ -79,3 +79,24 @@ testRule(rule, {
}
]
});

testRule(rule, {
ruleName,
config: [true],
syntax: "css-in-js",

accept: [
{
code: 'export default <h1 style={{ color: "#ffff" }}>Test</h1>;'
}
],

reject: [
{
code: 'export default <h1 style={{ color: "#fffff" }}>Test</h1>;',
message: messages.rejected("#fffff"),
line: 1,
column: 36
}
]
});
28 changes: 8 additions & 20 deletions lib/rules/color-no-invalid-hex/index.js
@@ -1,10 +1,11 @@
"use strict";

const declarationValueIndex = require("../../utils/declarationValueIndex");
const isValidHex = require("../../utils/isValidHex");
const report = require("../../utils/report");
const ruleMessages = require("../../utils/ruleMessages");
const styleSearch = require("style-search");
const validateOptions = require("../../utils/validateOptions");
const valueParser = require("postcss-value-parser");

const ruleName = "color-no-invalid-hex";

Expand All @@ -21,34 +22,21 @@ const rule = function(actual) {
}

root.walkDecls(decl => {
const declString = decl.toString();
valueParser(decl.value).walk(({ value, type, sourceIndex }) => {
if (type !== "word") return;

styleSearch({ source: declString, target: "#" }, match => {
// If there's not a colon, comma, or whitespace character before, we'll assume this is
// not intended to be a hex color, but is instead something like the
// hash in a url() argument
if (!/[:,\s]/.test(declString[match.startIndex - 1])) {
return;
}
const hexMatch = /^#[0-9A-Za-z]+/.exec(value);

const hexMatch = /^#[0-9A-Za-z]+/.exec(
declString.substr(match.startIndex)
);

if (!hexMatch) {
return;
}
if (!hexMatch) return;

const hexValue = hexMatch[0];

if (isValidHex(hexValue)) {
return;
}
if (isValidHex(hexValue)) return;

report({
message: messages.rejected(hexValue),
node: decl,
index: match.startIndex,
index: declarationValueIndex(decl) + sourceIndex,
result,
ruleName
});
Expand Down
3 changes: 1 addition & 2 deletions lib/rules/comment-word-blacklist/__tests__/index.js
Expand Up @@ -304,7 +304,6 @@ testRule(rule, {
]
});


testRule(rule, {
ruleName,
config: [/^TODO:/, "bad-word"],
Expand All @@ -323,4 +322,4 @@ testRule(rule, {
column: 1
}
]
})
});
Expand Up @@ -143,7 +143,6 @@ testRule(rule, {
]
});


testRule(rule, {
ruleName,

Expand Down
5 changes: 1 addition & 4 deletions lib/rules/font-family-no-duplicate-names/__tests__/index.js
Expand Up @@ -113,10 +113,7 @@ testRule(rule, {

testRule(rule, {
ruleName,
config: [
true,
{ ignoreFontFamilyNames: [/my-/] }
],
config: [true, { ignoreFontFamilyNames: [/my-/] }],

accept: [
{
Expand Down
5 changes: 1 addition & 4 deletions lib/rules/media-feature-name-no-unknown/__tests__/index.js
Expand Up @@ -212,10 +212,7 @@ testRule(rule, {

testRule(rule, {
ruleName,
config: [
true,
{ ignoreMediaFeatureNames: [/^my-/] }
],
config: [true, { ignoreMediaFeatureNames: [/^my-/] }],

accept: [
{
Expand Down
Expand Up @@ -105,12 +105,11 @@ testRule(rule, {
]
});


testRule(rule, {
ruleName,
config: [
{
"/resolution/": [/dpcm$/], // Only dpcm unit
"/resolution/": [/dpcm$/] // Only dpcm unit
}
],

Expand All @@ -135,7 +134,6 @@ testRule(rule, {
message: messages.rejected("min-resolution", "2dpi"),
line: 1,
column: 37
},

}
]
});
1 change: 0 additions & 1 deletion lib/rules/media-feature-name-whitelist/__tests__/index.js
Expand Up @@ -76,7 +76,6 @@ testRule(rule, {
]
});


testRule(rule, {
ruleName,
config: [/^my-/],
Expand Down
1 change: 0 additions & 1 deletion lib/rules/number-max-precision/__tests__/index.js
Expand Up @@ -204,7 +204,6 @@ testRule(rule, {
]
});


testRule(rule, {
ruleName,
config: [0, { ignoreUnits: [/^my-/] }],
Expand Down
1 change: 0 additions & 1 deletion lib/rules/property-blacklist/__tests__/index.js
Expand Up @@ -120,7 +120,6 @@ testRule(rule, {
]
});


testRule(rule, {
ruleName,

Expand Down
5 changes: 1 addition & 4 deletions lib/rules/property-no-vendor-prefix/__tests__/index.js
Expand Up @@ -146,10 +146,7 @@ testRule(rule, {

testRule(rule, {
ruleName,
config: [
true,
{ ignoreProperties: [/^animation-/i] }
],
config: [true, { ignoreProperties: [/^animation-/i] }],

accept: [
{
Expand Down
1 change: 0 additions & 1 deletion lib/rules/unit-blacklist/__tests__/index.js
Expand Up @@ -514,7 +514,6 @@ testRule(rule, {
]
});


testRule(rule, {
ruleName,

Expand Down
10 changes: 8 additions & 2 deletions lib/rules/unit-blacklist/index.js
Expand Up @@ -41,8 +41,14 @@ const rule = function(blacklistInput, options) {
optional: true,
actual: options,
possible: {
ignoreProperties: validateObjectWithArrayProps([_.isString, _.isRegExp]),
ignoreMediaFeatureNames: validateObjectWithArrayProps([_.isString, _.isRegExp]),
ignoreProperties: validateObjectWithArrayProps([
_.isString,
_.isRegExp
]),
ignoreMediaFeatureNames: validateObjectWithArrayProps([
_.isString,
_.isRegExp
])
}
}
);
Expand Down
5 changes: 4 additions & 1 deletion lib/rules/unit-whitelist/index.js
Expand Up @@ -32,7 +32,10 @@ const rule = function(whitelistInput, options) {
optional: true,
actual: options,
possible: {
ignoreProperties: validateObjectWithArrayProps([_.isString, _.isRegExp])
ignoreProperties: validateObjectWithArrayProps([
_.isString,
_.isRegExp
])
}
}
);
Expand Down
7 changes: 1 addition & 6 deletions lib/rules/value-keyword-case/__tests__/index.js
Expand Up @@ -2101,13 +2101,9 @@ testRule(rule, {
]
});


testRule(rule, {
ruleName,
config: [
"upper",
{ ignoreKeywords: [/^(f|F)lex$/] }
],
config: ["upper", { ignoreKeywords: [/^(f|F)lex$/] }],
fix: true,

accept: [
Expand Down Expand Up @@ -2177,7 +2173,6 @@ testRule(rule, {
]
});


testRule(rule, {
ruleName,
config: ["lower", { ignoreProperties: [/^(b|B)ackground$/] }],
Expand Down
106 changes: 58 additions & 48 deletions lib/utils/__tests__/validateObjectWithArrayProps.test.js
Expand Up @@ -2,51 +2,61 @@

const validateObjectWithArrayProps = require("../validateObjectWithArrayProps");

describe('validateObjectWithArrayProps', () => {
it('should return a function', () => {
expect(validateObjectWithArrayProps(x => x)).toBeInstanceOf(Function)
})

describe('returned validator', () => {
const validator = validateObjectWithArrayProps(x => x)

it('should return false if any of the object properties are not an array', () => {
expect(validator({
arrayProp: [1, 2],
nonArrayProp: 3
})).toBeFalsy()
})

it('should return false if any of the object properties array values do not pass the test', () => {
expect(validator({
arrayProp: [1, 2],
nonArrayProp: [0, 3]
})).toBeFalsy()
})

it('should return true otherwise', () => {
expect(validator({
arrayProp: [1, 2],
nonArrayProp: [3, 4]
})).toBeTruthy()
})
})

describe('returned validator with array', () => {
const validator = validateObjectWithArrayProps([x => x > 0, x => x < 0])

it('should accept an array of validators, any of which can return true', () => {
expect(validator({
arrayProp: [1, 2],
nonArrayProp: [-1, 3]
})).toBeTruthy()
})

it('should be false if none of the validators are true for any value', () => {
expect(validator({
arrayProp: [1, 2],
nonArrayProp: [-1, 0]
})).toBeFalsy()
})
})
})
describe("validateObjectWithArrayProps", () => {
it("should return a function", () => {
expect(validateObjectWithArrayProps(x => x)).toBeInstanceOf(Function);
});

describe("returned validator", () => {
const validator = validateObjectWithArrayProps(x => x);

it("should return false if any of the object properties are not an array", () => {
expect(
validator({
arrayProp: [1, 2],
nonArrayProp: 3
})
).toBeFalsy();
});

it("should return false if any of the object properties array values do not pass the test", () => {
expect(
validator({
arrayProp: [1, 2],
nonArrayProp: [0, 3]
})
).toBeFalsy();
});

it("should return true otherwise", () => {
expect(
validator({
arrayProp: [1, 2],
nonArrayProp: [3, 4]
})
).toBeTruthy();
});
});

describe("returned validator with array", () => {
const validator = validateObjectWithArrayProps([x => x > 0, x => x < 0]);

it("should accept an array of validators, any of which can return true", () => {
expect(
validator({
arrayProp: [1, 2],
nonArrayProp: [-1, 3]
})
).toBeTruthy();
});

it("should be false if none of the validators are true for any value", () => {
expect(
validator({
arrayProp: [1, 2],
nonArrayProp: [-1, 0]
})
).toBeFalsy();
});
});
});
8 changes: 3 additions & 5 deletions lib/utils/validateObjectWithArrayProps.js
Expand Up @@ -13,9 +13,7 @@ const _ = require("lodash");
* }
*/

module.exports = (
validator /*: Function */
) => (
module.exports = (validator /*: Function */) => (
value /*: Object*/
) /*: boolean*/ => {
if (!_.isPlainObject(value)) {
Expand All @@ -30,10 +28,10 @@ module.exports = (
// Make sure the array items are strings
return value[key].every(item => {
if (Array.isArray(validator)) {
return validator.some(v => v(item))
return validator.some(v => v(item));
}

return validator(item)
return validator(item);
});
});
};

0 comments on commit ee266b6

Please sign in to comment.