From 7e46d2e756965c254a5f4d821d23ab44494ace97 Mon Sep 17 00:00:00 2001
From: Weronika Olejniczak
<32842468+weronikaolejniczak@users.noreply.github.com>
Date: Wed, 2 Apr 2025 14:06:17 +0200
Subject: [PATCH] chore: update eslint-plugin-eui to 0.1.1 (#210082)
## Summary
Bring in the changes from https://github.com/elastic/eui/pull/8304,
specifically ESLint rules:
- `no-restricted-eui-imports`
- `no-css-color` (migrated from `@kbn/eslint-plugin-css`)
- `prefer-css-attribute-for-eui-components` (migrated from
`@kbn/eslint-plugin-css`)
Relates to https://github.com/elastic/eui/issues/8201,
https://github.com/elastic/eui-private/issues/275
## QA
### Instructions
1. Checkout this branch: `gh pr checkout 210082`.
2. Reinstall dependencies: `yarn kbn bootstrap`.
3. See output of ESLint. There should be no errors.
4. Test below cases.
### Test cases
#### `no-restricted-eui-imports`
Example files:
- JSON imports: `src/platform/packages/shared/kbn-ui-theme/src/theme.ts`
- `@kbn/ui-theme`:
`src/platform/plugins/private/vis_types/vega/public/data_model/utils.ts`
#### `no-css-color`
Example file:
`src/platform/plugins/shared/kibana_react/public/page_template/no_data_page/no_data_card/elastic_agent_card.tsx:50`

#### `prefer-css-attribute-for-eui-components`
Example file:
`x-pack/examples/alerting_example/public/alert_types/always_firing.tsx:166`
---
.eslintrc.js | 2 +-
.github/CODEOWNERS | 1 -
package.json | 3 +-
packages/kbn-eslint-config/.eslintrc.js | 33 +-
packages/kbn-eslint-plugin-css/README.mdx | 129 -----
packages/kbn-eslint-plugin-css/index.ts | 20 -
packages/kbn-eslint-plugin-css/jest.config.js | 14 -
packages/kbn-eslint-plugin-css/kibana.jsonc | 6 -
packages/kbn-eslint-plugin-css/package.json | 6 -
.../src/rules/no_css_color.test.ts | 266 ----------
.../src/rules/no_css_color.ts | 453 ------------------
...r_css_attribute_for_eui_components.test.ts | 85 ----
...prefer_css_attribute_for_eui_components.ts | 62 ---
packages/kbn-eslint-plugin-css/tsconfig.json | 11 -
.../packages/shared/kbn-ui-theme/src/theme.ts | 4 -
tsconfig.base.json | 2 -
.../attack/attack_chain/tactic/index.tsx | 4 +-
yarn.lock | 12 +-
18 files changed, 28 insertions(+), 1085 deletions(-)
delete mode 100644 packages/kbn-eslint-plugin-css/README.mdx
delete mode 100644 packages/kbn-eslint-plugin-css/index.ts
delete mode 100644 packages/kbn-eslint-plugin-css/jest.config.js
delete mode 100644 packages/kbn-eslint-plugin-css/kibana.jsonc
delete mode 100644 packages/kbn-eslint-plugin-css/package.json
delete mode 100644 packages/kbn-eslint-plugin-css/src/rules/no_css_color.test.ts
delete mode 100644 packages/kbn-eslint-plugin-css/src/rules/no_css_color.ts
delete mode 100644 packages/kbn-eslint-plugin-css/src/rules/prefer_css_attribute_for_eui_components.test.ts
delete mode 100644 packages/kbn-eslint-plugin-css/src/rules/prefer_css_attribute_for_eui_components.ts
delete mode 100644 packages/kbn-eslint-plugin-css/tsconfig.json
diff --git a/.eslintrc.js b/.eslintrc.js
index c70ec5d274a6..a9ec2e846c45 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -280,7 +280,7 @@ const RESTRICTED_IMPORTS = [
module.exports = {
root: true,
- extends: ['plugin:@elastic/eui/recommended', '@kbn/eslint-config'],
+ extends: ['@kbn/eslint-config'],
overrides: [
/**
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 3a90aecf7ac3..2e34b95a7a7f 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -55,7 +55,6 @@ packages/kbn-dependency-ownership @elastic/kibana-security
packages/kbn-dependency-usage @elastic/kibana-security
packages/kbn-docs-utils @elastic/kibana-operations
packages/kbn-eslint-config @elastic/kibana-operations
-packages/kbn-eslint-plugin-css @elastic/appex-sharedux
packages/kbn-eslint-plugin-disable @elastic/kibana-operations
packages/kbn-eslint-plugin-eslint @elastic/kibana-operations
packages/kbn-eslint-plugin-eui-a11y @elastic/obs-ux-infra_services-team
diff --git a/package.json b/package.json
index 9ae7d0f327e2..dc97960cfb90 100644
--- a/package.json
+++ b/package.json
@@ -1372,7 +1372,7 @@
"@cypress/debugging-proxy": "2.0.1",
"@cypress/grep": "^4.0.1",
"@cypress/webpack-preprocessor": "^6.0.2",
- "@elastic/eslint-plugin-eui": "0.0.2",
+ "@elastic/eslint-plugin-eui": "0.1.1",
"@elastic/makelogs": "^6.1.1",
"@elastic/synthetics": "^1.18.0",
"@emotion/babel-preset-css-prop": "^11.11.0",
@@ -1475,7 +1475,6 @@
"@kbn/es": "link:src/platform/packages/shared/kbn-es",
"@kbn/es-archiver": "link:src/platform/packages/shared/kbn-es-archiver",
"@kbn/eslint-config": "link:packages/kbn-eslint-config",
- "@kbn/eslint-plugin-css": "link:packages/kbn-eslint-plugin-css",
"@kbn/eslint-plugin-disable": "link:packages/kbn-eslint-plugin-disable",
"@kbn/eslint-plugin-eslint": "link:packages/kbn-eslint-plugin-eslint",
"@kbn/eslint-plugin-eui-a11y": "link:packages/kbn-eslint-plugin-eui-a11y",
diff --git a/packages/kbn-eslint-config/.eslintrc.js b/packages/kbn-eslint-config/.eslintrc.js
index f929bdb8a613..2d215f794abf 100644
--- a/packages/kbn-eslint-config/.eslintrc.js
+++ b/packages/kbn-eslint-config/.eslintrc.js
@@ -20,7 +20,13 @@
const { USES_STYLED_COMPONENTS } = require('@kbn/babel-preset/styled_components_files');
module.exports = {
- extends: ['./javascript.js', './typescript.js', './jest.js', './react.js'],
+ extends: [
+ './javascript.js',
+ './typescript.js',
+ './jest.js',
+ './react.js',
+ 'plugin:@elastic/eui/recommended',
+ ],
plugins: [
'@kbn/eslint-plugin-disable',
@@ -29,7 +35,7 @@ module.exports = {
'@kbn/eslint-plugin-telemetry',
'@kbn/eslint-plugin-i18n',
'@kbn/eslint-plugin-eui-a11y',
- '@kbn/eslint-plugin-css',
+ '@elastic/eui',
'eslint-plugin-depend',
'prettier',
],
@@ -129,16 +135,6 @@ module.exports = {
exclude: USES_STYLED_COMPONENTS,
disallowedMessage: `Prefer using @emotion/react instead. To use styled-components, ensure you plugin is enabled in packages/kbn-babel-preset/styled_components_files.js.`,
},
- ...[
- '@elastic/eui/dist/eui_theme_amsterdam_light.json',
- '@elastic/eui/dist/eui_theme_amsterdam_dark.json',
- '@elastic/eui/dist/eui_theme_borealis_light.json',
- '@elastic/eui/dist/eui_theme_borealis_dark.json',
- ].map((from) => ({
- from,
- to: false,
- disallowedMessage: `Use "@kbn/ui-theme" to access theme vars.`,
- })),
{
from: '@kbn/test/jest',
to: '@kbn/test-jest-helpers',
@@ -335,9 +331,20 @@ module.exports = {
'@kbn/imports/no_boundary_crossing': 'error',
'@kbn/imports/no_group_crossing_manifests': 'error',
'@kbn/imports/no_group_crossing_imports': 'error',
- '@kbn/css/no_css_color': 'warn',
'no-new-func': 'error',
'no-implied-eval': 'error',
'no-prototype-builtins': 'error',
+
+ /**
+ * EUI Team rules
+ */
+
+ '@elastic/eui/no-restricted-eui-imports': [
+ 'warn',
+ {
+ patterns: ['@kbn/ui-theme'],
+ message: 'For client-side, please use `useEuiTheme` instead.',
+ },
+ ],
},
};
diff --git a/packages/kbn-eslint-plugin-css/README.mdx b/packages/kbn-eslint-plugin-css/README.mdx
deleted file mode 100644
index 1e121657bc57..000000000000
--- a/packages/kbn-eslint-plugin-css/README.mdx
+++ /dev/null
@@ -1,129 +0,0 @@
----
-id: kibSharedUXEslintPluginCSS
-slug: /kibana-dev-docs/shared-ux/packages/kbn-eslint-plugin-css
-title: '@kbn/eslint-plugin-design-tokens'
-description: Custom ESLint rules to guardrails for using eui in the Kibana repository
-date: 2024-11-19
-tags: ['kibana', 'dev', 'contributor', 'shared_ux', 'eslint', 'eui']
----
-
-# Summary
-
-`@kbn/eslint-plugin-css` is an ESLint plugin providing custom ESLint rules to help setup guardrails for using eui in the Kibana repo especially around styling.
-
-The aim of this package is to help engineers to modify EUI components in a much complaint way.
-
-If a rule does not behave as you expect or you have an idea of how these rules can be improved, please reach out to the Shared UX team.
-
-# Rules
-
-## `@kbn/css/no_css_color`
-
-This rule warns engineers to not use literal css color in the codebase, particularly for CSS properties that apply color to
-either the html element or text nodes, but rather urge users to defer to using the color tokens provided by EUI.
-
-This rule kicks in on the following JSXAttributes; `style`, `className` and `css` and supports various approaches to providing styling declarations.
-
-### Example
-
-The following code:
-
-```
-// Filename: /x-pack/plugins/observability_solution/observability/public/my_component.tsx
-
-import React from 'react';
-import { EuiText } from '@elastic/eui';
-
-function MyComponent() {
- return (
- You know, for search
- )
-}
-```
-
-```
-// Filename: /x-pack/plugins/observability_solution/observability/public/my_component.tsx
-
-import React from 'react';
-import { EuiText } from '@elastic/eui';
-
-function MyComponent() {
-
- const style = {
- color: 'red'
- }
-
- return (
- You know, for search
- )
-}
-```
-
-```
-// Filename: /x-pack/plugins/observability_solution/observability/public/my_component.tsx
-
-import React from 'react';
-import { EuiText } from '@elastic/eui';
-
-function MyComponent() {
- const colorValue = '#dd4040';
-
- return (
- You know, for search
- )
-}
-```
-
-will all raise an eslint report with an appropriate message of severity that matches the configuration of the rule, further more all the examples above
-will also match for when the attribute in question is `css`. The `css` attribute will also raise a report the following cases below;
-
-```
-// Filename: /x-pack/plugins/observability_solution/observability/public/my_component.tsx
-
-import React from 'react';
-import { css } from '@emotion/css';
-import { EuiText } from '@elastic/eui';
-
-function MyComponent() {
- return (
- You know, for search
- )
-}
-```
-
-```
-// Filename: /x-pack/plugins/observability_solution/observability/public/my_component.tsx
-
-import React from 'react';
-import { EuiText } from '@elastic/eui';
-
-function MyComponent() {
- return (
- ({ color: '#dd4040' })}>You know, for search
- )
-}
-```
-
-A special case is also covered for the `className` attribute, where the rule will also raise a report for the following case below;
-
-
-```
-// Filename: /x-pack/plugins/observability_solution/observability/public/my_component.tsx
-
-import React from 'react';
-import { css } from '@emotion/css';
-import { EuiText } from '@elastic/eui';
-
-function MyComponent() {
- return (
- You know, for search
- )
-}
-```
-
-it's worth pointing out that although the examples provided are specific to EUI components, this rule applies to all JSX elements.
-
-## `@kbn/css/prefer_css_attributes_for_eui_components`
-
-This rule warns engineers to use the `css` attribute for EUI components instead of the `style` attribute.
-
diff --git a/packages/kbn-eslint-plugin-css/index.ts b/packages/kbn-eslint-plugin-css/index.ts
deleted file mode 100644
index 9ea4bcc67619..000000000000
--- a/packages/kbn-eslint-plugin-css/index.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the "Elastic License
- * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
- * Public License v 1"; you may not use this file except in compliance with, at
- * your election, the "Elastic License 2.0", the "GNU Affero General Public
- * License v3.0 only", or the "Server Side Public License, v 1".
- */
-
-import { NoCssColor } from './src/rules/no_css_color';
-import { PreferCSSAttributeForEuiComponents } from './src/rules/prefer_css_attribute_for_eui_components';
-
-/**
- * Custom ESLint rules, included as `'@kbn/eslint-plugin-design-tokens'` in the kibana eslint config
- * @internal
- */
-export const rules = {
- no_css_color: NoCssColor,
- prefer_css_attributes_for_eui_components: PreferCSSAttributeForEuiComponents,
-};
diff --git a/packages/kbn-eslint-plugin-css/jest.config.js b/packages/kbn-eslint-plugin-css/jest.config.js
deleted file mode 100644
index c8ae20237eae..000000000000
--- a/packages/kbn-eslint-plugin-css/jest.config.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the "Elastic License
- * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
- * Public License v 1"; you may not use this file except in compliance with, at
- * your election, the "Elastic License 2.0", the "GNU Affero General Public
- * License v3.0 only", or the "Server Side Public License, v 1".
- */
-
-module.exports = {
- preset: '@kbn/test',
- rootDir: '../..',
- roots: ['/packages/kbn-eslint-plugin-css'],
-};
diff --git a/packages/kbn-eslint-plugin-css/kibana.jsonc b/packages/kbn-eslint-plugin-css/kibana.jsonc
deleted file mode 100644
index 3ee8bff8736f..000000000000
--- a/packages/kbn-eslint-plugin-css/kibana.jsonc
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "type": "shared-common",
- "id": "@kbn/eslint-plugin-css",
- "devOnly": true,
- "owner": "@elastic/appex-sharedux"
-}
diff --git a/packages/kbn-eslint-plugin-css/package.json b/packages/kbn-eslint-plugin-css/package.json
deleted file mode 100644
index c811f06f27cb..000000000000
--- a/packages/kbn-eslint-plugin-css/package.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "name": "@kbn/eslint-plugin-css",
- "version": "1.0.0",
- "private": true,
- "license": "Elastic License 2.0 OR AGPL-3.0-only OR SSPL-1.0"
-}
diff --git a/packages/kbn-eslint-plugin-css/src/rules/no_css_color.test.ts b/packages/kbn-eslint-plugin-css/src/rules/no_css_color.test.ts
deleted file mode 100644
index d5323e7423ce..000000000000
--- a/packages/kbn-eslint-plugin-css/src/rules/no_css_color.test.ts
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the "Elastic License
- * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
- * Public License v 1"; you may not use this file except in compliance with, at
- * your election, the "Elastic License 2.0", the "GNU Affero General Public
- * License v3.0 only", or the "Server Side Public License, v 1".
- */
-
-import { RuleTester } from 'eslint';
-import { NoCssColor } from './no_css_color';
-
-const tsTester = [
- '@typescript-eslint/parser',
- new RuleTester({
- parser: require.resolve('@typescript-eslint/parser'),
- parserOptions: {
- sourceType: 'module',
- ecmaVersion: 2018,
- ecmaFeatures: {
- jsx: true,
- },
- },
- }),
-] as const;
-
-const babelTester = [
- '@babel/eslint-parser',
- new RuleTester({
- parser: require.resolve('@babel/eslint-parser'),
- parserOptions: {
- sourceType: 'module',
- ecmaVersion: 2018,
- requireConfigFile: false,
- babelOptions: {
- presets: ['@kbn/babel-preset/node_preset'],
- },
- },
- }),
-] as const;
-
-const invalid: RuleTester.InvalidTestCase[] = [
- {
- name: 'Raises an error when a CSS color is used in a JSX style attribute',
- filename: '/x-pack/plugins/observability_solution/observability/public/test_component.tsx',
- code: `
- import React from 'react';
-
- function TestComponent() {
- return (
- This is a test
- )
- }`,
- errors: [{ messageId: 'noCssColorSpecific' }],
- },
- {
- name: 'Raises an error when a CSS color references a string variable that is passed to style prop of a JSX element',
- filename: '/x-pack/plugins/observability_solution/observability/public/test_component.tsx',
- code: `
- import React from 'react';
-
- function TestComponent() {
- const codeColor = '#dd4040';
- return (
- This is a test
- )
- }`,
- errors: [{ messageId: 'noCSSColorSpecificDeclaredVariable' }],
- },
- {
- name: 'Raises an error when a CSS color is used in an object variable that is passed to style prop of a JSX element',
- filename: '/x-pack/plugins/observability_solution/observability/public/test_component.tsx',
- code: `
- import React from 'react';
-
- function TestComponent() {
- const codeStyle = { color: '#dd4040' };
- return (
- This is a test
- )
- }`,
- errors: [{ messageId: 'noCSSColorSpecificDeclaredVariable' }],
- },
- {
- name: 'Raises an error when an object property that is a literal CSS color is used for the background property in a JSX style attribute',
- filename: '/x-pack/plugins/observability_solution/observability/public/test_component.tsx',
- code: `
- import React from 'react';
-
- function TestComponent() {
- const baseStyle = { background: 'rgb(255, 255, 255)' };
-
- return (
- This is a test
- )
- }`,
- errors: [{ messageId: 'noCSSColorSpecificDeclaredVariable' }],
- },
- {
- name: 'Raises an error when a CSS color is used in a variable that is spread into another variable that is passed to style prop of a JSX element',
- filename: '/x-pack/plugins/observability_solution/observability/public/test_component.tsx',
- code: `
- import React from 'react';
-
- function TestComponent() {
- const baseStyle = { background: 'rgb(255, 255, 255)' };
- const codeStyle = { margin: '5px', ...baseStyle };
- return (
- This is a test
- )
- }`,
- errors: [{ messageId: 'noCSSColorSpecificDeclaredVariable' }],
- },
- {
- name: 'Raises an error when a CSS color is used for the background property in a JSX style attribute',
- filename: '/x-pack/plugins/observability_solution/observability/public/test_component.tsx',
- code: `
- import React from 'react';
-
- function TestComponent() {
- return (
- This is a test
- )
- }`,
- errors: [{ messageId: 'noCssColorSpecific' }],
- },
- {
- 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';
-
- function TestComponent() {
- return (
- This is a test
- )
- }`,
- errors: [{ messageId: 'noCssColorSpecific' }],
- },
- {
- name: 'Raises an error when a CSS color for the color property is used in with the tagged template css function',
- filename: '/x-pack/plugins/observability_solution/observability/public/test_component.tsx',
- code: `
- import { css } from '@emotion/css';
-
- const codeColor = css\` color: #dd4040; \`;
- `,
- errors: [{ messageId: 'noCssColor' }],
- },
- {
- 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';
- import { css } from '@emotion/css';
-
- function TestComponent() {
- return (
- This is a test
- )
- }`,
- errors: [{ messageId: 'noCssColor' }],
- },
- {
- name: 'Raises an error when a CSS color for the color property is used in a JSX className attribute for EuiComponents with the css template function defined outside the scope of the component',
- filename: '/x-pack/plugins/observability_solution/observability/public/test_component.tsx',
- code: `
- import React from 'react';
- import { css } from '@emotion/css';
-
- const codeCss = css({
- color: '#dd4040',
- })
-
- function TestComponent() {
- return (
- This is a test
- )
- }`,
- errors: [{ messageId: 'noCSSColorSpecificDeclaredVariable' }],
- },
- {
- name: 'Raises an error when a CSS color for the color property is used in a JSX className attribute for EuiComponents with the css template function defined outside the scope of the component',
- filename: '/x-pack/plugins/observability_solution/observability/public/test_component.tsx',
- code: `
- import React from 'react';
- import { css } from '@emotion/css';
-
- const codeCss = css\` color: #dd4040; \`
-
- function TestComponent() {
- return (
- This is a test
- )
- }`,
- errors: [{ messageId: 'noCssColor' }],
- },
- {
- 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';
-
- function TestComponent() {
- return (
- ({ color: '#dd4040' })}>This is a test
- )
- }`,
- errors: [{ messageId: 'noCssColorSpecific' }],
- },
- {
- 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';
-
- function TestComponent() {
- return (
- This is a test
- )
- }`,
- errors: [{ messageId: 'noCssColorSpecific' }],
- },
- {
- name: 'Raises an error when a CSS color for the color property is used in a JSX className attribute for EuiComponents with the css template function',
- filename: '/x-pack/plugins/observability_solution/observability/public/test_component.tsx',
- code: `
- import React from 'react';
- import { css } from '@emotion/css';
-
- function TestComponent() {
- return (
- This is a test
- )
- }`,
- errors: [{ messageId: 'noCssColor' }],
- },
-];
-
-const valid: RuleTester.ValidTestCase[] = [
- {
- name: 'Does not raise an error when a CSS color is not used in a JSX css prop attribute',
- filename: '/x-pack/plugins/observability_solution/observability/public/test_component.tsx',
- code: `
- import React from 'react';
- import { EuiCode } from '@elastic/eui';
- import { css } from '@emotion/react';
- function TestComponent() {
- return (
- This is a test
- )
- }`,
- },
-];
-
-for (const [name, tester] of [tsTester, babelTester]) {
- describe(name, () => {
- tester.run('@kbn/no_css_color', NoCssColor, {
- valid,
- invalid,
- });
- });
-}
diff --git a/packages/kbn-eslint-plugin-css/src/rules/no_css_color.ts b/packages/kbn-eslint-plugin-css/src/rules/no_css_color.ts
deleted file mode 100644
index fb73fe53fda0..000000000000
--- a/packages/kbn-eslint-plugin-css/src/rules/no_css_color.ts
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the "Elastic License
- * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
- * Public License v 1"; you may not use this file except in compliance with, at
- * your election, the "Elastic License 2.0", the "GNU Affero General Public
- * License v3.0 only", or the "Server Side Public License, v 1".
- */
-
-import type { Rule } from 'eslint';
-import { CSSStyleDeclaration } from 'cssstyle';
-import type { TSESTree } from '@typescript-eslint/typescript-estree';
-
-/**
- * @description List of superset css properties that can apply color to html box element elements and text nodes, leveraging the
- * css style package allows us to directly singly check for these properties even if the actual declaration was written using the shorthand form
- */
-const propertiesSupportingCssColor = ['color', 'background', 'border'];
-
-/**
- * @description Builds off the existing color definition to match css declarations that can apply color to
- * html elements and text nodes for string declarations
- */
-const htmlElementColorDeclarationRegex = RegExp(
- String.raw`(${propertiesSupportingCssColor.join('|')})`
-);
-
-const checkPropertySpecifiesInvalidCSSColor = ([property, value]: string[]) => {
- if (!property || !value) return false;
-
- const style = new CSSStyleDeclaration();
-
- // @ts-ignore the types for this packages specifies an index signature of number, alongside other valid CSS properties
- style[property.trim()] = typeof value === 'string' ? value.trim() : value;
-
- const anchor = propertiesSupportingCssColor.find((resolvedProperty) =>
- property.includes(resolvedProperty)
- );
-
- if (!anchor) return false;
-
- // build the resolved color property to check if the value is a string after parsing the style declaration
- const resolvedColorProperty = anchor === 'color' ? 'color' : anchor + 'Color';
-
- // in trying to keep this rule simple, it's enough if we get a value back, because if it was an identifier we would have been able to set a value within this invocation
- // @ts-ignore the types for this packages specifics an index signature of number, alongside other valid CSS properties
- return Boolean(style[resolvedColorProperty]);
-};
-
-const resolveMemberExpressionRoot = (node: TSESTree.MemberExpression): TSESTree.Identifier => {
- if (node.object.type === 'MemberExpression') {
- return resolveMemberExpressionRoot(node.object);
- }
-
- return node.object as TSESTree.Identifier;
-};
-
-/**
- * @description method to inspect values of interest found on an object
- */
-const raiseReportIfPropertyHasInvalidCssColor = (
- context: Rule.RuleContext,
- propertyNode: TSESTree.Property,
- messageToReport: Rule.ReportDescriptor
-) => {
- let didReport = false;
-
- if (
- propertyNode.key.type === 'Identifier' &&
- !htmlElementColorDeclarationRegex.test(propertyNode.key.name)
- ) {
- return didReport;
- }
-
- if (propertyNode.value.type === 'Literal') {
- if (
- (didReport = checkPropertySpecifiesInvalidCSSColor([
- // @ts-expect-error the key name is present in this scenario
- propertyNode.key.name,
- propertyNode.value.value,
- ]))
- ) {
- context.report(messageToReport);
- }
- } else if (propertyNode.value.type === 'Identifier') {
- const identifierDeclaration = context.sourceCode
- // @ts-expect-error
- .getScope(propertyNode)
- .variables.find(
- (variable) => variable.name === (propertyNode.value as TSESTree.Identifier).name!
- );
-
- if (
- identifierDeclaration?.defs[0].node.init?.type === 'Literal' &&
- checkPropertySpecifiesInvalidCSSColor([
- // @ts-expect-error the key name is present in this scenario
- propertyNode.key.name,
- (identifierDeclaration.defs[0].node.init as TSESTree.Literal).value as string,
- ])
- ) {
- context.report({
- loc: propertyNode.value.loc,
- messageId: 'noCSSColorSpecificDeclaredVariable',
- data: {
- // @ts-expect-error the key name is always present else this code will not execute
- property: String(propertyNode.key.name),
- line: String(propertyNode.value.loc.start.line),
- variableName: propertyNode.value.name,
- },
- });
-
- didReport = true;
- }
- } else if (propertyNode.value.type === 'MemberExpression') {
- // @ts-expect-error we ignore the case where this node could be a private identifier
- const MemberExpressionLeafName = propertyNode.value.property.name;
- const memberExpressionRootName = resolveMemberExpressionRoot(propertyNode.value).name;
-
- const expressionRootDeclaration = context.sourceCode
- // @ts-expect-error
- .getScope(propertyNode)
- .variables.find((variable) => variable.name === memberExpressionRootName);
-
- const expressionRootDeclarationInit = expressionRootDeclaration?.defs[0].node.init;
-
- if (expressionRootDeclarationInit?.type === 'ObjectExpression') {
- (expressionRootDeclarationInit as TSESTree.ObjectExpression).properties.forEach(
- (property) => {
- // This is a naive approach expecting the value to be at depth 1, we should actually be traversing the object to the same depth as the expression
- if (
- property.type === 'Property' &&
- property.key.type === 'Identifier' &&
- property.key?.name === MemberExpressionLeafName
- ) {
- raiseReportIfPropertyHasInvalidCssColor(context, property, {
- loc: propertyNode.value.loc,
- messageId: 'noCSSColorSpecificDeclaredVariable',
- data: {
- // @ts-expect-error the key name is always present else this code will not execute
- property: String(propertyNode.key.name),
- line: String(propertyNode.value.loc.start.line),
- variableName: memberExpressionRootName,
- },
- });
- }
- }
- );
- } else if (expressionRootDeclarationInit?.type === 'CallExpression') {
- // TODO: if this object was returned from invoking a function the best we can do is probably validate that the method invoked is one that returns an euitheme object
- }
- }
-
- return didReport;
-};
-
-/**
- *
- * @description style object declaration have a depth of 1, this function handles the properties of the object
- */
-const handleObjectProperties = (
- context: Rule.RuleContext,
- propertyParentNode: TSESTree.JSXAttribute,
- property: TSESTree.ObjectLiteralElement,
- reportMessage: Rule.ReportDescriptor
-) => {
- if (property.type === 'Property') {
- raiseReportIfPropertyHasInvalidCssColor(context, property, reportMessage);
- } else if (property.type === 'SpreadElement') {
- const spreadElementIdentifierName = (property.argument as TSESTree.Identifier).name;
-
- const spreadElementDeclaration = context.sourceCode
- // @ts-expect-error
- .getScope(propertyParentNode!.value.expression!)
- .references.find((ref) => ref.identifier.name === spreadElementIdentifierName)?.resolved;
-
- if (!spreadElementDeclaration) {
- return;
- }
-
- reportMessage = {
- loc: propertyParentNode.loc,
- messageId: 'noCSSColorSpecificDeclaredVariable',
- data: {
- // @ts-expect-error the key name is always present else this code will not execute
- property: String(property.argument.name),
- variableName: spreadElementIdentifierName,
- line: String(property.loc.start.line),
- },
- };
-
- const spreadElementDeclarationNode = spreadElementDeclaration.defs[0].node.init;
-
- // evaluate only statically defined declarations, other possibilities like callExpressions in this context complicate things
- if (spreadElementDeclarationNode?.type === 'ObjectExpression') {
- (spreadElementDeclarationNode as TSESTree.ObjectExpression).properties.forEach(
- (spreadProperty) => {
- handleObjectProperties(context, propertyParentNode, spreadProperty, reportMessage);
- }
- );
- }
- }
-};
-
-export const NoCssColor: Rule.RuleModule = {
- meta: {
- type: 'suggestion',
- docs: {
- description: 'Use color definitions from eui theme as opposed to CSS color values',
- category: 'Best Practices',
- recommended: true,
- url: 'https://eui.elastic.co/#/theming/colors/values',
- },
- messages: {
- noCSSColorSpecificDeclaredVariable:
- 'Avoid using a literal CSS color value for "{{property}}", use an EUI theme color instead in declared variable {{variableName}} on line {{line}}',
- noCssColorSpecific:
- 'Avoid using a literal CSS color value for "{{property}}", use an EUI theme color instead',
- noCssColor: 'Avoid using a literal CSS color value, use an EUI theme color instead',
- },
- schema: [],
- },
- create(context) {
- return {
- // accounts for instances where declarations are created using the template tagged css function
- TaggedTemplateExpression(node) {
- if (
- node.tag.type !== 'Identifier' ||
- (node.tag.type === 'Identifier' && node.tag.name !== 'css')
- ) {
- return;
- }
-
- for (let i = 0; i < node.quasi.quasis.length; i++) {
- const declarationTemplateNode = node.quasi.quasis[i];
-
- if (htmlElementColorDeclarationRegex.test(declarationTemplateNode.value.raw)) {
- const cssText = declarationTemplateNode.value.raw.replace(/(\{|\}|\\n)/g, '').trim();
-
- cssText.split(';').forEach((declaration) => {
- if (
- declaration.length > 0 &&
- checkPropertySpecifiesInvalidCSSColor(declaration.split(':'))
- ) {
- context.report({
- node: declarationTemplateNode,
- messageId: 'noCssColor',
- });
- }
- });
- }
- }
- },
- JSXAttribute(node: TSESTree.JSXAttribute) {
- if (!(node.name.name === 'style' || node.name.name === 'css')) {
- return;
- }
-
- /**
- * @description Accounts for instances where a variable is used to define a style object
- *
- * @example
- * const codeStyle = { color: '#dd4040' };
- * This is an example
- *
- * @example
- * const codeStyle = { color: '#dd4040' };
- * This is an example
- *
- * @example
- * const codeStyle = css({ color: '#dd4040' });
- * This is an example
- */
- if (
- node.value?.type === 'JSXExpressionContainer' &&
- node.value.expression.type === 'Identifier'
- ) {
- const styleVariableName = node.value.expression.name;
-
- const nodeScope = context.sourceCode.getScope(node.value.expression);
-
- const variableDeclarationMatches = nodeScope.references.find(
- (ref) => ref.identifier.name === styleVariableName
- )?.resolved;
-
- let variableInitializationNode;
-
- if ((variableInitializationNode = variableDeclarationMatches?.defs?.[0]?.node?.init)) {
- if (variableInitializationNode.type === 'ObjectExpression') {
- // @ts-ignore
- variableInitializationNode.properties.forEach((property) => {
- handleObjectProperties(context, node, property, {
- loc: property.loc,
- messageId: 'noCSSColorSpecificDeclaredVariable',
- data: {
- property:
- property.type === 'SpreadElement'
- ? String(property.argument.name)
- : String(property.key.name),
- variableName: styleVariableName,
- line: String(property.loc.start.line),
- },
- });
- });
- } else if (
- variableInitializationNode.type === 'CallExpression' &&
- variableInitializationNode.callee.name === 'css'
- ) {
- const cssFunctionArgument = variableInitializationNode.arguments[0];
-
- if (cssFunctionArgument.type === 'ObjectExpression') {
- // @ts-ignore
- cssFunctionArgument.properties.forEach((property) => {
- handleObjectProperties(context, node, property, {
- loc: node.loc,
- messageId: 'noCSSColorSpecificDeclaredVariable',
- data: {
- property:
- property.type === 'SpreadElement'
- ? String(property.argument.name)
- : String(property.key.name),
- variableName: styleVariableName,
- line: String(property.loc.start.line),
- },
- });
- });
- }
- }
- }
-
- return;
- }
-
- /**
- *
- * @description Accounts for instances where a style object is inlined in the JSX attribute
- *
- * @example
- * This is an example
- *
- * @example
- * This is an example
- *
- * @example
- * const styleRules = { color: '#dd4040' };
- * This is an example
- *
- * @example
- * const styleRules = { color: '#dd4040' };
- * This is an example
- */
- if (
- node.value?.type === 'JSXExpressionContainer' &&
- node.value.expression.type === 'ObjectExpression'
- ) {
- const declarationPropertiesNode = node.value.expression.properties;
-
- declarationPropertiesNode?.forEach((property) => {
- handleObjectProperties(context, node, property, {
- loc: property.loc,
- messageId: 'noCssColorSpecific',
- data: {
- property:
- property.type === 'SpreadElement'
- ? // @ts-expect-error the key name is always present else this code will not execute
- String(property.argument.name)
- : // @ts-expect-error the key name is always present else this code will not execute
- String(property.key.name),
- },
- });
- });
-
- return;
- }
-
- if (node.name.name === 'css' && node.value?.type === 'JSXExpressionContainer') {
- /**
- * @example
- * This is an example
- */
- if (node.value.expression.type === 'TemplateLiteral') {
- for (let i = 0; i < node.value.expression.quasis.length; i++) {
- const declarationTemplateNode = node.value.expression.quasis[i];
-
- if (htmlElementColorDeclarationRegex.test(declarationTemplateNode.value.raw)) {
- const cssText = declarationTemplateNode.value.raw
- .replace(/(\{|\}|\\n)/g, '')
- .trim();
-
- cssText.split(';').forEach((declaration) => {
- if (
- declaration.length > 0 &&
- checkPropertySpecifiesInvalidCSSColor(declaration.split(':'))
- ) {
- context.report({
- node: declarationTemplateNode,
- messageId: 'noCssColor',
- });
- }
- });
- }
- }
- }
-
- /**
- * @example
- * ({ color: '#dd4040' })}>This is an example
- */
- if (
- node.value.expression.type === 'FunctionExpression' ||
- node.value.expression.type === 'ArrowFunctionExpression'
- ) {
- let declarationPropertiesNode: TSESTree.Property[] = [];
-
- if (node.value.expression.body.type === 'ObjectExpression') {
- // @ts-expect-error
- declarationPropertiesNode = node.value.expression.body.properties;
- }
-
- if (node.value.expression.body.type === 'BlockStatement') {
- const functionReturnStatementNode = node.value.expression.body.body?.find((_node) => {
- return _node.type === 'ReturnStatement';
- });
-
- if (!functionReturnStatementNode) {
- return;
- }
-
- declarationPropertiesNode = // @ts-expect-error
- (functionReturnStatementNode as TSESTree.ReturnStatement).argument?.properties;
- }
-
- if (!declarationPropertiesNode.length) {
- return;
- }
-
- declarationPropertiesNode.forEach((property) => {
- handleObjectProperties(context, node, property, {
- loc: property.loc,
- messageId: 'noCssColorSpecific',
- data: {
- // @ts-expect-error the key name is always present else this code will not execute
- property: property.key.name,
- },
- });
- });
-
- return;
- }
- }
- },
- };
- },
-};
diff --git a/packages/kbn-eslint-plugin-css/src/rules/prefer_css_attribute_for_eui_components.test.ts b/packages/kbn-eslint-plugin-css/src/rules/prefer_css_attribute_for_eui_components.test.ts
deleted file mode 100644
index f1534ec5c861..000000000000
--- a/packages/kbn-eslint-plugin-css/src/rules/prefer_css_attribute_for_eui_components.test.ts
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the "Elastic License
- * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
- * Public License v 1"; you may not use this file except in compliance with, at
- * your election, the "Elastic License 2.0", the "GNU Affero General Public
- * License v3.0 only", or the "Server Side Public License, v 1".
- */
-
-import { RuleTester } from 'eslint';
-import { PreferCSSAttributeForEuiComponents } from './prefer_css_attribute_for_eui_components';
-
-const tsTester = [
- '@typescript-eslint/parser',
- new RuleTester({
- parser: require.resolve('@typescript-eslint/parser'),
- parserOptions: {
- sourceType: 'module',
- ecmaVersion: 2018,
- ecmaFeatures: {
- jsx: true,
- },
- },
- }),
-] as const;
-
-const babelTester = [
- '@babel/eslint-parser',
- new RuleTester({
- parser: require.resolve('@babel/eslint-parser'),
- parserOptions: {
- sourceType: 'module',
- ecmaVersion: 2018,
- requireConfigFile: false,
- babelOptions: {
- presets: ['@kbn/babel-preset/node_preset'],
- },
- },
- }),
-] as const;
-
-const invalid: RuleTester.InvalidTestCase[] = [
- {
- name: 'Prefer the JSX css attribute for EUI components',
- filename: '/x-pack/plugins/observability_solution/observability/public/test_component.tsx',
- code: `
- import React from 'react';
-
- function TestComponent() {
- return (
- This is a test
- )
- }`,
- errors: [
- {
- messageId: 'preferCSSAttributeForEuiComponents',
- },
- ],
- output: `
- import React from 'react';
-
- function TestComponent() {
- return (
- This is a test
- )
- }`,
- },
-];
-
-const valid: RuleTester.ValidTestCase[] = [
- {
- name: invalid[0].name,
- filename: invalid[0].filename,
- code: invalid[0].output as string,
- },
-];
-
-for (const [name, tester] of [tsTester, babelTester]) {
- describe(name, () => {
- tester.run('@kbn/prefer_css_attribute_for_eui_components', PreferCSSAttributeForEuiComponents, {
- valid,
- invalid,
- });
- });
-}
diff --git a/packages/kbn-eslint-plugin-css/src/rules/prefer_css_attribute_for_eui_components.ts b/packages/kbn-eslint-plugin-css/src/rules/prefer_css_attribute_for_eui_components.ts
deleted file mode 100644
index f2b8bfd7b7d7..000000000000
--- a/packages/kbn-eslint-plugin-css/src/rules/prefer_css_attribute_for_eui_components.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the "Elastic License
- * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
- * Public License v 1"; you may not use this file except in compliance with, at
- * your election, the "Elastic License 2.0", the "GNU Affero General Public
- * License v3.0 only", or the "Server Side Public License, v 1".
- */
-
-import type { Rule } from 'eslint';
-import type { TSESTree } from '@typescript-eslint/typescript-estree';
-import type { Identifier, Node } from 'estree';
-
-export const PreferCSSAttributeForEuiComponents: Rule.RuleModule = {
- meta: {
- type: 'suggestion',
- docs: {
- description: 'Prefer the JSX css attribute for EUI components',
- category: 'Best Practices',
- recommended: true,
- },
- messages: {
- preferCSSAttributeForEuiComponents: 'Prefer the css attribute for EUI components',
- },
- fixable: 'code',
- schema: [],
- },
- create(context) {
- const isNamedEuiComponentRegex = /^Eui[A-Z]*/;
-
- return {
- JSXOpeningElement(node: TSESTree.JSXOpeningElement) {
- if (isNamedEuiComponentRegex.test((node.name as unknown as Identifier).name)) {
- let styleAttrNode: TSESTree.JSXAttribute | undefined;
-
- if (
- // @ts-expect-error the returned result is somehow typed as a union of JSXAttribute and JSXAttributeSpread
- (styleAttrNode = node.attributes.find(
- (attr) => attr.type === 'JSXAttribute' && attr.name.name === 'style'
- ))
- ) {
- context.report({
- node: styleAttrNode?.parent! as Node,
- messageId: 'preferCSSAttributeForEuiComponents',
- fix(fixer) {
- const cssAttr = node.attributes.find(
- (attr) => attr.type === 'JSXAttribute' && attr.name.name === 'css'
- );
-
- if (cssAttr) {
- return null;
- }
-
- return fixer.replaceTextRange(styleAttrNode?.name?.range!, 'css');
- },
- });
- }
- }
- },
- };
- },
-};
diff --git a/packages/kbn-eslint-plugin-css/tsconfig.json b/packages/kbn-eslint-plugin-css/tsconfig.json
deleted file mode 100644
index a6dec1c1a62c..000000000000
--- a/packages/kbn-eslint-plugin-css/tsconfig.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "extends": "../../tsconfig.base.json",
- "compilerOptions": {
- "outDir": "target/types",
- "types": ["jest", "node"],
- "lib": ["es2021"]
- },
- "include": ["**/*.ts"],
- "exclude": ["target/**/*"],
- "kbn_references": []
-}
diff --git a/src/platform/packages/shared/kbn-ui-theme/src/theme.ts b/src/platform/packages/shared/kbn-ui-theme/src/theme.ts
index 2f3703f3f7e8..e22498671cfd 100644
--- a/src/platform/packages/shared/kbn-ui-theme/src/theme.ts
+++ b/src/platform/packages/shared/kbn-ui-theme/src/theme.ts
@@ -7,14 +7,10 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/
-/* eslint-disable-next-line @kbn/eslint/module_migration */
import { default as v8Light } from '@elastic/eui/dist/eui_theme_amsterdam_light.json';
-/* eslint-disable-next-line @kbn/eslint/module_migration */
import { default as v8Dark } from '@elastic/eui/dist/eui_theme_amsterdam_dark.json';
-/* eslint-disable-next-line @kbn/eslint/module_migration */
import { default as borealisLight } from '@elastic/eui/dist/eui_theme_borealis_light.json';
-/* eslint-disable-next-line @kbn/eslint/module_migration */
import { default as borealisDark } from '@elastic/eui/dist/eui_theme_borealis_dark.json';
const globals: any = typeof window === 'undefined' ? {} : window;
diff --git a/tsconfig.base.json b/tsconfig.base.json
index 76737f5afd46..cc0eb69e4cd8 100644
--- a/tsconfig.base.json
+++ b/tsconfig.base.json
@@ -860,8 +860,6 @@
"@kbn/es-ui-shared-plugin/*": ["src/platform/plugins/shared/es_ui_shared/*"],
"@kbn/eslint-config": ["packages/kbn-eslint-config"],
"@kbn/eslint-config/*": ["packages/kbn-eslint-config/*"],
- "@kbn/eslint-plugin-css": ["packages/kbn-eslint-plugin-css"],
- "@kbn/eslint-plugin-css/*": ["packages/kbn-eslint-plugin-css/*"],
"@kbn/eslint-plugin-disable": ["packages/kbn-eslint-plugin-disable"],
"@kbn/eslint-plugin-disable/*": ["packages/kbn-eslint-plugin-disable/*"],
"@kbn/eslint-plugin-eslint": ["packages/kbn-eslint-plugin-eslint"],
diff --git a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/tabs/attack_discovery_tab/attack/attack_chain/tactic/index.tsx b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/tabs/attack_discovery_tab/attack/attack_chain/tactic/index.tsx
index 7399357d7104..44d6f6a961ae 100644
--- a/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/tabs/attack_discovery_tab/attack/attack_chain/tactic/index.tsx
+++ b/x-pack/solutions/security/plugins/security_solution/public/attack_discovery/pages/results/attack_discovery_panel/tabs/attack_discovery_tab/attack/attack_chain/tactic/index.tsx
@@ -61,7 +61,7 @@ const TacticComponent: React.FC = ({ detected, tactic }) => {
grow={false}
>