Skip to content

Commit

Permalink
add support for more css properties that accept color values
Browse files Browse the repository at this point in the history
  • Loading branch information
eokoneyo committed Nov 19, 2024
1 parent d0f6855 commit c844595
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 63 deletions.
8 changes: 4 additions & 4 deletions packages/kbn-eslint-plugin-css/src/rules/no_css_color.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ const invalid: RuleTester.InvalidTestCase[] = [
errors: [{ messageId: 'noCssColor' }],
},
{
name: 'Raises an error when a CSS color is used in a JSX css attribute for EuiComponents',
name: 'Raises an error when a CSS color for the color property is used in a JSX css attribute for EuiComponents',
filename: '/x-pack/plugins/observability_solution/observability/public/test_component.tsx',
code: `
import React from 'react';
Expand All @@ -67,7 +67,7 @@ const invalid: RuleTester.InvalidTestCase[] = [
errors: [{ messageId: 'noCssColor' }],
},
{
name: 'Raises an error when a CSS color is used in a JSX css attribute for EuiComponents with the css template function',
name: 'Raises an error when a CSS color for the color property is used in a JSX css attribute for EuiComponents with the css template function',
filename: '/x-pack/plugins/observability_solution/observability/public/test_component.tsx',
code: `
import React from 'react';
Expand All @@ -80,7 +80,7 @@ const invalid: RuleTester.InvalidTestCase[] = [
errors: [{ messageId: 'noCssColor' }],
},
{
name: 'Raises an error when a CSS color is used in a JSX css attribute for EuiComponents with an arrow function',
name: 'Raises an error when a CSS color for the color property is used in a JSX css attribute for EuiComponents with an arrow function',
filename: '/x-pack/plugins/observability_solution/observability/public/test_component.tsx',
code: `
import React from 'react';
Expand All @@ -93,7 +93,7 @@ const invalid: RuleTester.InvalidTestCase[] = [
errors: [{ messageId: 'noCssColor' }],
},
{
name: 'Raises an error when a CSS color is used in a JSX css attribute for EuiComponents with a regular function',
name: 'Raises an error when a CSS color for the color property is used in a JSX css attribute for EuiComponents with a regular function',
filename: '/x-pack/plugins/observability_solution/observability/public/test_component.tsx',
code: `
import React from 'react';
Expand Down
114 changes: 55 additions & 59 deletions packages/kbn-eslint-plugin-css/src/rules/no_css_color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,49 @@
import type { Rule } from 'eslint';
import type { TSESTree } from '@typescript-eslint/typescript-estree';

/**
* @description Regex to match css color values,
* see {@link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value} for definitions of valid css color values
*/
const cssColorRegex = /(#|rgb|hsl|hwb|lab|lch|oklab).*/;

/**
* @description List of css properties that can that can apply color to html box element and text node
*/
const propertiesSupportingCssColor = ['color', 'background', 'backgroundColor', 'border'];

/**
* @description Builds off the existing color definition regex to match css declarations that can apply color to html elements and text nodes
*/
const htmlElementColorDeclarationRegex = RegExp(
String.raw`(${propertiesSupportingCssColor.join('|')})\:\s?(\'|\")?${cssColorRegex.source}`
);

const raiseReportIfPropertyHasCssColor = (
context: Rule.RuleContext,
node: TSESTree.ObjectLiteralElement
) => {
let didReport: boolean;

// checks if property value is a css color value for instances where style declaration is computed from an object
if (
(didReport = Boolean(
node.type === 'Property' &&
node.key.type === 'Identifier' &&
node.value.type === 'Literal' &&
propertiesSupportingCssColor.indexOf(node.key.name) > -1 &&
cssColorRegex.test(String(node.value.value) ?? '')
))
) {
context.report({
loc: node.loc,
messageId: 'noCssColor',
});
}

return didReport;
};

export const NoCssColor: Rule.RuleModule = {
meta: {
type: 'suggestion',
Expand All @@ -33,7 +76,7 @@ export const NoCssColor: Rule.RuleModule = {

if (node.name.name === 'style') {
/**
* @example <EuiCode style={`{ color: '#dd4040' }`}>This is a test</EuiCode>
* @example <EuiCode style={`{ color: '#dd4040' }`}>This is an example</EuiCode>
*/
if (
node.value &&
Expand All @@ -42,11 +85,7 @@ export const NoCssColor: Rule.RuleModule = {
) {
const declarationTemplateNode = node.value.expression.quasis[0];

if (
/color\:\s?(\'|\")?(#|rgb|hsl|hwb|lab|lch|oklab)/.test(
declarationTemplateNode.value.raw
)
) {
if (htmlElementColorDeclarationRegex.test(declarationTemplateNode.value.raw)) {
context.report({
node: declarationTemplateNode,
messageId: 'noCssColor',
Expand All @@ -55,7 +94,7 @@ export const NoCssColor: Rule.RuleModule = {
}

/**
* @example <EuiCode style={{ color: '#dd4040' }}>This is a test</EuiCode>
* @example <EuiCode style={{ color: '#dd4040' }}>This is an example</EuiCode>
*/
if (
node.value &&
Expand All @@ -70,19 +109,8 @@ export const NoCssColor: Rule.RuleModule = {

for (let i = 0; i < declarationTemplateNode.length; i++) {
const property = declarationTemplateNode[i];
if (
property.type === 'Property' &&
property.key.type === 'Identifier' &&
property.key.name === 'color' &&
property.value.type === 'Literal' &&
property.value.value &&
/(#|rgb|hsl|hwb|lab|lch|oklab).*/.test(String(property.value.value))
) {
context.report({
node: property.key,
messageId: 'noCssColor',
});

if (raiseReportIfPropertyHasCssColor(context, property)) {
break;
}
}
Expand All @@ -91,7 +119,7 @@ export const NoCssColor: Rule.RuleModule = {

if (node.name.name === 'css') {
/**
* @example <EuiCode css={`{ color: '#dd4040' }`}>This is a test</EuiCode>
* @example <EuiCode css={`{ color: '#dd4040' }`}>This is an example</EuiCode>
*/
if (
node.value &&
Expand All @@ -100,11 +128,7 @@ export const NoCssColor: Rule.RuleModule = {
) {
const declarationTemplateNode = node.value.expression.quasis[0];

if (
/color\:\s?(\'|\")(#|rgb|hsl|hwb|lab|lch|oklab)/.test(
declarationTemplateNode.value.raw
)
) {
if (htmlElementColorDeclarationRegex.test(declarationTemplateNode.value.raw)) {
context.report({
node: declarationTemplateNode,
messageId: 'noCssColor',
Expand All @@ -113,7 +137,7 @@ export const NoCssColor: Rule.RuleModule = {
}

/**
* @example <EuiCode css={{ color: '#dd4040' }}>This is a test</EuiCode>
* @example <EuiCode css={{ color: '#dd4040' }}>This is an example</EuiCode>
*/
if (
node.value &&
Expand All @@ -129,26 +153,14 @@ export const NoCssColor: Rule.RuleModule = {
for (let i = 0; i < declarationTemplateNode.length; i++) {
const property = declarationTemplateNode[i];

if (
property.type === 'Property' &&
property.key.type === 'Identifier' &&
property.key.name === 'color' &&
property.value.type === 'Literal' &&
property.value.value &&
/(#|rgb|hsl|hwb|lab|lch|oklab).*/.test(String(property.value.value))
) {
context.report({
node: property.key,
messageId: 'noCssColor',
});

if (raiseReportIfPropertyHasCssColor(context, property)) {
break;
}
}
}

/**
* @example <EuiCode css={css`{ color: #dd4040 }`}>This is a test</EuiCode>
* @example <EuiCode css={css`{ color: #dd4040 }`}>This is an example</EuiCode>
*/
if (
node.value &&
Expand All @@ -159,11 +171,7 @@ export const NoCssColor: Rule.RuleModule = {
) {
const declarationTemplateNode = node.value.expression.quasi.quasis[0];

if (
/color\:\s?(\'|\")(#|rgb|hsl|hwb|lab|lch|oklab)/.test(
declarationTemplateNode.value.raw
)
) {
if (htmlElementColorDeclarationRegex.test(declarationTemplateNode.value.raw)) {
context.report({
node: declarationTemplateNode,
messageId: 'noCssColor',
Expand All @@ -172,7 +180,7 @@ export const NoCssColor: Rule.RuleModule = {
}

/**
* @example <EuiCode css={() => ({ color: '#dd4040' })}>This is a test</EuiCode>
* @example <EuiCode css={() => ({ color: '#dd4040' })}>This is an example</EuiCode>
*/
if (
node.value &&
Expand Down Expand Up @@ -207,19 +215,7 @@ export const NoCssColor: Rule.RuleModule = {
for (let i = 0; i < declarationPropertiesNode.length; i++) {
const property = declarationPropertiesNode[i];

if (
property.type === 'Property' &&
property.key.type === 'Identifier' &&
property.key.name === 'color' &&
property.value.type === 'Literal' &&
property.value.value &&
/(#|rgb|hsl|hwb|lab|lch|oklab).*/.test(String(property.value.value))
) {
context.report({
node: property.key,
messageId: 'noCssColor',
});

if (raiseReportIfPropertyHasCssColor(context, property)) {
break;
}
}
Expand Down

0 comments on commit c844595

Please sign in to comment.