@elastic/eslint-plugin-eui 2.15.0 → 2.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +125 -0
  2. package/lib/cjs/index.js +10 -1
  3. package/lib/cjs/rules/a11y/no_nested_copy_tooltip.d.ts +3 -0
  4. package/lib/cjs/rules/a11y/no_nested_copy_tooltip.d.ts.map +1 -0
  5. package/lib/cjs/rules/a11y/no_nested_copy_tooltip.js +84 -0
  6. package/lib/cjs/rules/a11y/tooltip_button_icon_wrap.d.ts.map +1 -1
  7. package/lib/cjs/rules/a11y/tooltip_button_icon_wrap.js +29 -1
  8. package/lib/cjs/rules/a11y/tooltip_no_interactive_content.d.ts.map +1 -1
  9. package/lib/cjs/rules/a11y/tooltip_no_interactive_content.js +17 -45
  10. package/lib/cjs/rules/button_group_no_invalid_children.d.ts +3 -0
  11. package/lib/cjs/rules/button_group_no_invalid_children.d.ts.map +1 -0
  12. package/lib/cjs/rules/button_group_no_invalid_children.js +159 -0
  13. package/lib/cjs/rules/callout_prefer_props_for_content.d.ts.map +1 -1
  14. package/lib/cjs/rules/callout_prefer_props_for_content.js +93 -156
  15. package/lib/cjs/rules/no_deprecated_icon_aliases.d.ts +174 -0
  16. package/lib/cjs/rules/no_deprecated_icon_aliases.d.ts.map +1 -0
  17. package/lib/cjs/rules/no_deprecated_icon_aliases.js +302 -0
  18. package/lib/cjs/utils/flat_map.d.ts +2 -0
  19. package/lib/cjs/utils/flat_map.d.ts.map +1 -0
  20. package/lib/cjs/utils/flat_map.js +24 -0
  21. package/lib/cjs/utils/has_meaningful_attr.d.ts +20 -0
  22. package/lib/cjs/utils/has_meaningful_attr.d.ts.map +1 -0
  23. package/lib/cjs/utils/has_meaningful_attr.js +61 -0
  24. package/lib/cjs/utils/is_fragment.d.ts +8 -0
  25. package/lib/cjs/utils/is_fragment.d.ts.map +1 -0
  26. package/lib/cjs/utils/is_fragment.js +26 -0
  27. package/lib/cjs/utils/walk_jsx_children.d.ts +30 -0
  28. package/lib/cjs/utils/walk_jsx_children.d.ts.map +1 -0
  29. package/lib/cjs/utils/walk_jsx_children.js +210 -0
  30. package/lib/esm/index.js +9 -0
  31. package/lib/esm/index.js.map +1 -1
  32. package/lib/esm/rules/a11y/no_nested_copy_tooltip.d.ts +2 -0
  33. package/lib/esm/rules/a11y/no_nested_copy_tooltip.js +84 -0
  34. package/lib/esm/rules/a11y/no_nested_copy_tooltip.js.map +1 -0
  35. package/lib/esm/rules/a11y/tooltip_button_icon_wrap.js +31 -0
  36. package/lib/esm/rules/a11y/tooltip_button_icon_wrap.js.map +1 -1
  37. package/lib/esm/rules/a11y/tooltip_no_interactive_content.js +19 -42
  38. package/lib/esm/rules/a11y/tooltip_no_interactive_content.js.map +1 -1
  39. package/lib/esm/rules/button_group_no_invalid_children.d.ts +2 -0
  40. package/lib/esm/rules/button_group_no_invalid_children.js +198 -0
  41. package/lib/esm/rules/button_group_no_invalid_children.js.map +1 -0
  42. package/lib/esm/rules/callout_prefer_props_for_content.js +75 -112
  43. package/lib/esm/rules/callout_prefer_props_for_content.js.map +1 -1
  44. package/lib/esm/rules/no_deprecated_icon_aliases.d.ts +173 -0
  45. package/lib/esm/rules/no_deprecated_icon_aliases.js +307 -0
  46. package/lib/esm/rules/no_deprecated_icon_aliases.js.map +1 -0
  47. package/lib/esm/utils/flat_map.d.ts +1 -0
  48. package/lib/esm/utils/flat_map.js +22 -0
  49. package/lib/esm/utils/flat_map.js.map +1 -0
  50. package/lib/esm/utils/has_meaningful_attr.d.ts +19 -0
  51. package/lib/esm/utils/has_meaningful_attr.js +55 -0
  52. package/lib/esm/utils/has_meaningful_attr.js.map +1 -0
  53. package/lib/esm/utils/is_fragment.d.ts +7 -0
  54. package/lib/esm/utils/is_fragment.js +26 -0
  55. package/lib/esm/utils/is_fragment.js.map +1 -0
  56. package/lib/esm/utils/walk_jsx_children.d.ts +29 -0
  57. package/lib/esm/utils/walk_jsx_children.js +213 -0
  58. package/lib/esm/utils/walk_jsx_children.js.map +1 -0
  59. package/package.json +1 -1
@@ -0,0 +1,210 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.walkJsxChildren = walkJsxChildren;
7
+ var _flat_map = require("./flat_map");
8
+ var _is_fragment = require("./is_fragment");
9
+ /*
10
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
11
+ * or more contributor license agreements. Licensed under the Elastic License
12
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
13
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
14
+ * Side Public License, v 1.
15
+ */
16
+
17
+ // A variable is only safely resolvable if it is never reassigned. A second
18
+ // write means the value at the point of use can't be determined statically.
19
+ function isReassigned(variable) {
20
+ return variable.references.filter(ref => ref.isWrite()).length > 1;
21
+ }
22
+
23
+ /**
24
+ * Resolves an expression-context Identifier to the node its variable was
25
+ * initialized with (e.g. the `<EuiButton />` in `const btn = <EuiButton />`).
26
+ * Returns null for anything that can't be resolved safely: imports, function
27
+ * parameters, reassigned variables, or missing initializers.
28
+ */
29
+ function resolveIdentifierValue(sourceCode, node) {
30
+ let scope = sourceCode.getScope(node);
31
+ while (scope) {
32
+ const ref = scope.references.find(r => r.identifier === node);
33
+ if (ref) {
34
+ const variable = ref.resolved;
35
+ if (!variable || isReassigned(variable)) return null;
36
+ const def = variable.defs[0];
37
+ if (!def || def.type !== 'Variable' || !def.node.init) return null;
38
+ return def.node.init;
39
+ }
40
+ scope = scope.upper;
41
+ }
42
+ return null;
43
+ }
44
+
45
+ /**
46
+ * Collects all return-statement arguments within a block body, recursing into
47
+ * `if`/`else` branches and `switch` cases. Does not recurse into nested
48
+ * functions - those have their own return scope. Used to validate block-body
49
+ * arrow functions.
50
+ */
51
+ function collectReturnValues(node) {
52
+ switch (node.type) {
53
+ case 'BlockStatement':
54
+ return (0, _flat_map.flatMap)(node.body, collectReturnValues);
55
+ case 'ReturnStatement':
56
+ return node.argument ? [node.argument] : [];
57
+ case 'IfStatement':
58
+ return [...collectReturnValues(node.consequent), ...(node.alternate ? collectReturnValues(node.alternate) : [])];
59
+ case 'SwitchStatement':
60
+ return (0, _flat_map.flatMap)(node.cases, c => (0, _flat_map.flatMap)(c.consequent, collectReturnValues));
61
+ default:
62
+ return [];
63
+ }
64
+ }
65
+
66
+ /**
67
+ * Resolves a JSX component name (e.g. `Buttons` in `<Buttons />`) to the
68
+ * nodes returned by its local arrow-function definition, if one exists.
69
+ *
70
+ * Handles both expression-body (`() => <expr>`) and block-body
71
+ * (`() => { return <expr>; }`) arrow functions. Imports, class components,
72
+ * and reassigned variables return null — those stay opaque.
73
+ */
74
+ function resolveLocalComponent(sourceCode, name, refNode) {
75
+ let scope = sourceCode.getScope(refNode);
76
+ while (scope) {
77
+ const variable = scope.variables.find(v => v.name === name);
78
+ if (variable) {
79
+ if (isReassigned(variable)) return null;
80
+ const def = variable.defs[0];
81
+ if (!def || def.type !== 'Variable' || !def.node.init) return null;
82
+ const init = def.node.init;
83
+ if (init.type !== 'ArrowFunctionExpression') return null;
84
+ if (init.body.type !== 'BlockStatement') return [init.body];
85
+ const returns = collectReturnValues(init.body);
86
+ return returns.length > 0 ? returns : null;
87
+ }
88
+ scope = scope.upper;
89
+ }
90
+ return null;
91
+ }
92
+ function walkJsxChild(node, visit, sourceCode, visited, shouldSkip) {
93
+ const walk = n => walkJsxChild(n, visit, sourceCode, visited, shouldSkip);
94
+ switch (node.type) {
95
+ case 'JSXElement':
96
+ {
97
+ if ((0, _is_fragment.isFragment)(node.openingElement)) {
98
+ node.children.forEach(walk);
99
+ return;
100
+ }
101
+ if (sourceCode) {
102
+ const {
103
+ name
104
+ } = node.openingElement;
105
+ if (name.type === 'JSXIdentifier' && !visited.has(name.name)) {
106
+ const resolved = resolveLocalComponent(sourceCode, name.name, node.openingElement);
107
+ if (resolved !== null) {
108
+ visited.add(name.name);
109
+ resolved.forEach(walk);
110
+ visited.delete(name.name);
111
+ return;
112
+ }
113
+ }
114
+ }
115
+ if (shouldSkip?.(node)) {
116
+ node.children.forEach(walk);
117
+ return;
118
+ }
119
+ visit(node);
120
+ return;
121
+ }
122
+ case 'JSXFragment':
123
+ node.children.forEach(walk);
124
+ return;
125
+ case 'JSXExpressionContainer':
126
+ if (node.expression.type !== 'JSXEmptyExpression') walk(node.expression);
127
+ return;
128
+ case 'LogicalExpression':
129
+ walk(node.left);
130
+ walk(node.right);
131
+ return;
132
+ case 'ConditionalExpression':
133
+ walk(node.consequent);
134
+ walk(node.alternate);
135
+ return;
136
+ case 'ArrayExpression':
137
+ node.elements.forEach(el => {
138
+ if (el && el.type !== 'SpreadElement') walk(el);
139
+ });
140
+ return;
141
+ case 'Identifier':
142
+ if (sourceCode) {
143
+ const resolved = resolveIdentifierValue(sourceCode, node);
144
+ if (resolved) {
145
+ walk(resolved);
146
+ return;
147
+ }
148
+ }
149
+ return;
150
+ case 'ArrowFunctionExpression':
151
+ if (node.body.type !== 'BlockStatement') {
152
+ walk(node.body);
153
+ } else {
154
+ collectReturnValues(node.body).forEach(walk);
155
+ }
156
+ return;
157
+ case 'CallExpression':
158
+ {
159
+ const {
160
+ callee,
161
+ arguments: args
162
+ } = node;
163
+ if (callee.type === 'MemberExpression' && callee.property.type === 'Identifier' && callee.property.name === 'map' && args.length >= 1 && args[0].type === 'ArrowFunctionExpression') {
164
+ const fn = args[0];
165
+ if (fn.body.type !== 'BlockStatement') {
166
+ walk(fn.body);
167
+ } else {
168
+ collectReturnValues(fn.body).forEach(walk);
169
+ }
170
+ }
171
+ return;
172
+ }
173
+ case 'JSXText':
174
+ case 'Literal':
175
+ case 'TemplateLiteral':
176
+ case 'MemberExpression':
177
+ visit(node);
178
+ return;
179
+ default:
180
+ return;
181
+ }
182
+ }
183
+
184
+ /**
185
+ * Recursively walks JSX children, expanding structural nodes transparently
186
+ * and calling `visit` for each content node.
187
+ *
188
+ * Always expanded (structural nodes):
189
+ * - `<>...</>`, `<Fragment>`, `<React.Fragment>` (transparent grouping)
190
+ * - `{expr}` (JSXExpressionContainer)
191
+ * - `{a && b}`, `{a || b}`, `{a ?? b}` (LogicalExpression → both sides)
192
+ * - `{c ? a : b}` (ConditionalExpression → both branches)
193
+ * - `{[a, b]}` (ArrayExpression → each element)
194
+ * - `{(arg) => <El />}` (ArrowFunctionExpression)
195
+ * - `{arr.map(fn)}` (CallExpression `.map()` with arrow-fn callback)
196
+ *
197
+ * With `options.sourceCode`: Identifiers and local arrow-fn components are
198
+ * also expanded via scope lookup when resolvable.
199
+ *
200
+ * `options.shouldSkip` - when provided, called for each JSXElement reached
201
+ * (after fragment and local-component checks). Returning true skips the
202
+ * element itself and recurses into its children instead. Use this to make
203
+ * layout wrappers or non-interactive shells transparent to the visitor.
204
+ *
205
+ * `visit` is called for leaf nodes: JSXElement, JSXText, Literal,
206
+ * TemplateLiteral, MemberExpression.
207
+ */
208
+ function walkJsxChildren(node, visit, options = {}) {
209
+ walkJsxChild(node, visit, options.sourceCode, new Set(), options.shouldSkip);
210
+ }
package/lib/esm/index.js CHANGED
@@ -14,6 +14,7 @@ const consistent_is_invalid_props_1 = require("./rules/a11y/consistent_is_invali
14
14
  const href_or_on_click_1 = require("./rules/href_or_on_click");
15
15
  const require_href_for_link_1 = require("./rules/require_href_for_link");
16
16
  const no_css_color_1 = require("./rules/no_css_color");
17
+ const no_nested_copy_tooltip_1 = require("./rules/a11y/no_nested_copy_tooltip");
17
18
  const no_restricted_eui_imports_1 = require("./rules/no_restricted_eui_imports");
18
19
  const no_static_z_index_1 = require("./rules/no_static_z_index");
19
20
  const no_unnamed_interactive_element_1 = require("./rules/a11y/no_unnamed_interactive_element");
@@ -28,6 +29,8 @@ const badge_accessibility_rules_1 = require("./rules/a11y/badge_accessibility_ru
28
29
  const icon_accessibility_rules_1 = require("./rules/a11y/icon_accessibility_rules");
29
30
  const tooltip_no_interactive_content_1 = require("./rules/a11y/tooltip_no_interactive_content");
30
31
  const tooltip_button_icon_wrap_1 = require("./rules/a11y/tooltip_button_icon_wrap");
32
+ const no_deprecated_icon_aliases_1 = require("./rules/no_deprecated_icon_aliases");
33
+ const button_group_no_invalid_children_1 = require("./rules/button_group_no_invalid_children");
31
34
  const config = {
32
35
  rules: {
33
36
  'accessible-interactive-element': accessible_interactive_element_1.AccessibleInteractiveElements,
@@ -36,6 +39,8 @@ const config = {
36
39
  'consistent-is-invalid-props': consistent_is_invalid_props_1.ConsistentIsInvalidProps,
37
40
  'href-or-on-click': href_or_on_click_1.HrefOnClick,
38
41
  'no-css-color': no_css_color_1.NoCssColor,
42
+ 'no-deprecated-icon-aliases': no_deprecated_icon_aliases_1.NoDeprecatedIconAliases,
43
+ 'no-nested-copy-tooltip': no_nested_copy_tooltip_1.NoNestedCopyTooltip,
39
44
  'no-restricted-eui-imports': no_restricted_eui_imports_1.NoRestrictedEuiImports,
40
45
  'no-static-z-index': no_static_z_index_1.NoStaticZIndex,
41
46
  'no-unnamed-interactive-element': no_unnamed_interactive_element_1.NoUnnamedInteractiveElement,
@@ -51,17 +56,21 @@ const config = {
51
56
  'require-href-for-link': require_href_for_link_1.RequireHrefForLink,
52
57
  'tooltip-no-interactive-content': tooltip_no_interactive_content_1.TooltipNoInteractiveContent,
53
58
  'tooltip-button-icon-wrap': tooltip_button_icon_wrap_1.TooltipButtonIconWrap,
59
+ 'button-group-no-invalid-children': button_group_no_invalid_children_1.ButtonGroupNoInvalidChildren,
54
60
  },
55
61
  configs: {
56
62
  recommended: {
57
63
  plugins: ['@elastic/eslint-plugin-eui'],
58
64
  rules: {
59
65
  '@elastic/eui/accessible-interactive-element': 'warn',
66
+ '@elastic/eui/button-group-no-invalid-children': 'error',
60
67
  '@elastic/eui/callout-announce-on-mount': 'warn',
61
68
  '@elastic/eui/callout-prefer-props-for-content': 'warn',
62
69
  '@elastic/eui/consistent-is-invalid-props': 'warn',
63
70
  '@elastic/eui/href-or-on-click': 'warn',
64
71
  '@elastic/eui/no-css-color': 'warn',
72
+ '@elastic/eui/no-deprecated-icon-aliases': 'warn',
73
+ '@elastic/eui/no-nested-copy-tooltip': 'warn',
65
74
  '@elastic/eui/no-restricted-eui-imports': 'warn',
66
75
  '@elastic/eui/no-static-z-index': 'warn',
67
76
  '@elastic/eui/no-unnamed-interactive-element': 'warn',
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAEH,gGAA4F;AAC5F,sFAAgF;AAChF,+FAAwF;AACxF,0FAAoF;AACpF,+DAAuD;AACvD,yEAAmE;AACnE,uDAAkD;AAClD,iFAA2E;AAC3E,iEAA2D;AAC3D,gGAA0F;AAC1F,gFAA0E;AAC1E,0EAAoE;AACpE,8FAAuF;AACvF,8EAAyE;AACzE,wFAA4F;AAC5F,oFAA+E;AAC/E,iHAAyG;AACzG,sFAAoF;AACpF,oFAAkF;AAClF,gGAA0F;AAC1F,oFAA8E;AAE9E,MAAM,MAAM,GAAG;IACb,KAAK,EAAE;QACL,gCAAgC,EAAE,8DAA6B;QAC/D,2BAA2B,EAAE,kDAAsB;QACnD,kCAAkC,EAAE,+DAA4B;QAChE,6BAA6B,EAAE,sDAAwB;QACvD,kBAAkB,EAAE,8BAAW;QAC/B,cAAc,EAAE,yBAAU;QAC1B,2BAA2B,EAAE,kDAAsB;QACnD,mBAAmB,EAAE,kCAAc;QACnC,gCAAgC,EAAE,4DAA2B;QAC7D,wBAAwB,EAAE,4CAAmB;QAC7C,qBAAqB,EAAE,sCAAgB;QACvC,+BAA+B,EAAE,yDAAyB;QAC1D,uBAAuB,EAAE,2CAAmB;QAC5C,4BAA4B,EAAE,8DAAiC;QAC/D,0BAA0B,EAAE,iDAAsB;QAClD,2CAA2C,EACzC,gFAAoC;QACtC,2BAA2B,EAAE,sDAA0B;QACvD,0BAA0B,EAAE,oDAAyB;QACrD,uBAAuB,EAAE,0CAAkB;QAC3C,gCAAgC,EAAE,4DAA2B;QAC7D,0BAA0B,EAAE,gDAAqB;KAClD;IACD,OAAO,EAAE;QACP,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,4BAA4B,CAAC;YACvC,KAAK,EAAE;gBACL,6CAA6C,EAAE,MAAM;gBACrD,wCAAwC,EAAE,MAAM;gBAChD,+CAA+C,EAAE,MAAM;gBACvD,0CAA0C,EAAE,MAAM;gBAClD,+BAA+B,EAAE,MAAM;gBACvC,2BAA2B,EAAE,MAAM;gBACnC,wCAAwC,EAAE,MAAM;gBAChD,gCAAgC,EAAE,MAAM;gBACxC,6CAA6C,EAAE,MAAM;gBACrD,qCAAqC,EAAE,MAAM;gBAC7C,kCAAkC,EAAE,MAAM;gBAC1C,4CAA4C,EAAE,MAAM;gBACpD,oCAAoC,EAAE,MAAM;gBAC5C,yCAAyC,EAAE,MAAM;gBACjD,uCAAuC,EAAE,MAAM;gBAC/C,wDAAwD,EAAE,MAAM;gBAChE,wCAAwC,EAAE,MAAM;gBAChD,uCAAuC,EAAE,MAAM;gBAC/C,oCAAoC,EAAE,MAAM;gBAC5C,6CAA6C,EAAE,MAAM;gBACrD,uCAAuC,EAAE,MAAM;aAChD;SACF;KACF;CACF,CAAC;AAEF,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;AAEH,gGAA4F;AAC5F,sFAAgF;AAChF,+FAAwF;AACxF,0FAAoF;AACpF,+DAAuD;AACvD,yEAAmE;AACnE,uDAAkD;AAClD,gFAA0E;AAC1E,iFAA2E;AAC3E,iEAA2D;AAC3D,gGAA0F;AAC1F,gFAA0E;AAC1E,0EAAoE;AACpE,8FAAuF;AACvF,8EAAyE;AACzE,wFAA4F;AAC5F,oFAA+E;AAC/E,iHAAyG;AACzG,sFAAoF;AACpF,oFAAkF;AAClF,gGAA0F;AAC1F,oFAA8E;AAC9E,mFAA6E;AAC7E,+FAAwF;AAExF,MAAM,MAAM,GAAG;IACb,KAAK,EAAE;QACL,gCAAgC,EAAE,8DAA6B;QAC/D,2BAA2B,EAAE,kDAAsB;QACnD,kCAAkC,EAAE,+DAA4B;QAChE,6BAA6B,EAAE,sDAAwB;QACvD,kBAAkB,EAAE,8BAAW;QAC/B,cAAc,EAAE,yBAAU;QAC1B,4BAA4B,EAAE,oDAAuB;QACrD,wBAAwB,EAAE,4CAAmB;QAC7C,2BAA2B,EAAE,kDAAsB;QACnD,mBAAmB,EAAE,kCAAc;QACnC,gCAAgC,EAAE,4DAA2B;QAC7D,wBAAwB,EAAE,4CAAmB;QAC7C,qBAAqB,EAAE,sCAAgB;QACvC,+BAA+B,EAAE,yDAAyB;QAC1D,uBAAuB,EAAE,2CAAmB;QAC5C,4BAA4B,EAAE,8DAAiC;QAC/D,0BAA0B,EAAE,iDAAsB;QAClD,2CAA2C,EACzC,gFAAoC;QACtC,2BAA2B,EAAE,sDAA0B;QACvD,0BAA0B,EAAE,oDAAyB;QACrD,uBAAuB,EAAE,0CAAkB;QAC3C,gCAAgC,EAAE,4DAA2B;QAC7D,0BAA0B,EAAE,gDAAqB;QACjD,kCAAkC,EAAE,+DAA4B;KACjE;IACD,OAAO,EAAE;QACP,WAAW,EAAE;YACX,OAAO,EAAE,CAAC,4BAA4B,CAAC;YACvC,KAAK,EAAE;gBACL,6CAA6C,EAAE,MAAM;gBACrD,+CAA+C,EAAE,OAAO;gBACxD,wCAAwC,EAAE,MAAM;gBAChD,+CAA+C,EAAE,MAAM;gBACvD,0CAA0C,EAAE,MAAM;gBAClD,+BAA+B,EAAE,MAAM;gBACvC,2BAA2B,EAAE,MAAM;gBACnC,yCAAyC,EAAE,MAAM;gBACjD,qCAAqC,EAAE,MAAM;gBAC7C,wCAAwC,EAAE,MAAM;gBAChD,gCAAgC,EAAE,MAAM;gBACxC,6CAA6C,EAAE,MAAM;gBACrD,qCAAqC,EAAE,MAAM;gBAC7C,kCAAkC,EAAE,MAAM;gBAC1C,4CAA4C,EAAE,MAAM;gBACpD,oCAAoC,EAAE,MAAM;gBAC5C,yCAAyC,EAAE,MAAM;gBACjD,uCAAuC,EAAE,MAAM;gBAC/C,wDAAwD,EAAE,MAAM;gBAChE,wCAAwC,EAAE,MAAM;gBAChD,uCAAuC,EAAE,MAAM;gBAC/C,oCAAoC,EAAE,MAAM;gBAC5C,6CAA6C,EAAE,MAAM;gBACrD,uCAAuC,EAAE,MAAM;aAChD;SACF;KACF;CACF,CAAC;AAEF,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { ESLintUtils } from '@typescript-eslint/utils';
2
+ export declare const NoNestedCopyTooltip: ESLintUtils.RuleModule<"redundantTooltipWrapper", [], unknown, ESLintUtils.RuleListener>;
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ /*
3
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
4
+ * or more contributor license agreements. Licensed under the Elastic License
5
+ * 2.0 and the Server Side Public License, v 1; you may not use this file except
6
+ * in compliance with, at your election, the Elastic License 2.0 or the Server
7
+ * Side Public License, v 1.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.NoNestedCopyTooltip = void 0;
11
+ const utils_1 = require("@typescript-eslint/utils");
12
+ const has_meaningful_attr_1 = require("../../utils/has_meaningful_attr");
13
+ const COPY = 'EuiCopy';
14
+ const TOOLTIP = 'EuiToolTip';
15
+ const BEFORE_MESSAGE = 'beforeMessage';
16
+ /**
17
+ * Resolves the JSX element returned by the `EuiCopy` render-prop child.
18
+ *
19
+ * `EuiCopy` renders its children through a function (`children(copy)`), so the
20
+ * "first child" is the root JSX element that function returns. This handles
21
+ * both implicit arrow returns (`(copy) => <El />`) and block bodies with an
22
+ * explicit `return` statement. Non-render-prop children (e.g. a leading JSX
23
+ * comment) are skipped so the render-prop function is still found.
24
+ */
25
+ function getRenderPropRootElement(node) {
26
+ const renderProp = node.children.find((child) => child.type === 'JSXExpressionContainer' &&
27
+ (child.expression.type === 'ArrowFunctionExpression' ||
28
+ child.expression.type === 'FunctionExpression'));
29
+ if (!renderProp)
30
+ return null;
31
+ const expression = renderProp.expression;
32
+ let { body } = expression;
33
+ if (body.type === 'BlockStatement') {
34
+ const returnStatement = body.body.find((statement) => statement.type === 'ReturnStatement');
35
+ if (!returnStatement?.argument)
36
+ return null;
37
+ body = returnStatement.argument;
38
+ }
39
+ return body.type === 'JSXElement' ? body : null;
40
+ }
41
+ function isToolTipElement(element) {
42
+ const { name } = element.openingElement;
43
+ return name.type === 'JSXIdentifier' && name.name === TOOLTIP;
44
+ }
45
+ exports.NoNestedCopyTooltip = utils_1.ESLintUtils.RuleCreator.withoutDocs({
46
+ create(context) {
47
+ return {
48
+ JSXElement(node) {
49
+ const { openingElement } = node;
50
+ if (openingElement.name.type !== 'JSXIdentifier' ||
51
+ openingElement.name.name !== COPY) {
52
+ return;
53
+ }
54
+ // A statically empty/falsy `beforeMessage` renders no `EuiCopy`
55
+ // tooltip, so a child `EuiToolTip` is not redundant — skip those.
56
+ if (!(0, has_meaningful_attr_1.hasMeaningfulAttr)(openingElement, BEFORE_MESSAGE))
57
+ return;
58
+ const rootElement = getRenderPropRootElement(node);
59
+ if (!rootElement || !isToolTipElement(rootElement))
60
+ return;
61
+ context.report({
62
+ node: rootElement,
63
+ messageId: 'redundantTooltipWrapper',
64
+ });
65
+ },
66
+ };
67
+ },
68
+ meta: {
69
+ type: 'problem',
70
+ docs: {
71
+ description: `Disallow wrapping the ${COPY} render-prop child in an ${TOOLTIP} when \`${BEFORE_MESSAGE}\` is set`,
72
+ },
73
+ schema: [],
74
+ messages: {
75
+ redundantTooltipWrapper: [
76
+ `${COPY} already wraps its child in an ${TOOLTIP} and uses \`${BEFORE_MESSAGE}\` as that tooltip's content.`,
77
+ `Wrapping the child in another ${TOOLTIP} creates a nested, conflicting tooltip.`,
78
+ `Remove the ${TOOLTIP} wrapper and move its message into the \`${BEFORE_MESSAGE}\` prop instead.`,
79
+ ].join(' '),
80
+ },
81
+ },
82
+ defaultOptions: [],
83
+ });
84
+ //# sourceMappingURL=no_nested_copy_tooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"no_nested_copy_tooltip.js","sourceRoot":"","sources":["../../../../src/rules/a11y/no_nested_copy_tooltip.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAEH,oDAAsE;AACtE,yEAAoE;AAEpE,MAAM,IAAI,GAAG,SAAS,CAAC;AACvB,MAAM,OAAO,GAAG,YAAY,CAAC;AAC7B,MAAM,cAAc,GAAG,eAAe,CAAC;AAEvC;;;;;;;;GAQG;AACH,SAAS,wBAAwB,CAC/B,IAAyB;IAEzB,MAAM,UAAU,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CACnC,CAAC,KAAK,EAA4C,EAAE,CAClD,KAAK,CAAC,IAAI,KAAK,wBAAwB;QACvC,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,KAAK,yBAAyB;YAClD,KAAK,CAAC,UAAU,CAAC,IAAI,KAAK,oBAAoB,CAAC,CACpD,CAAC;IAEF,IAAI,CAAC,UAAU;QAAE,OAAO,IAAI,CAAC;IAE7B,MAAM,UAAU,GAAG,UAAU,CAAC,UAEC,CAAC;IAEhC,IAAI,EAAE,IAAI,EAAE,GAAG,UAAU,CAAC;IAE1B,IAAI,IAAI,CAAC,IAAI,KAAK,gBAAgB,EAAE,CAAC;QACnC,MAAM,eAAe,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CACpC,CAAC,SAAS,EAAyC,EAAE,CACnD,SAAS,CAAC,IAAI,KAAK,iBAAiB,CACvC,CAAC;QAEF,IAAI,CAAC,eAAe,EAAE,QAAQ;YAAE,OAAO,IAAI,CAAC;QAE5C,IAAI,GAAG,eAAe,CAAC,QAAQ,CAAC;IAClC,CAAC;IAED,OAAO,IAAI,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AAClD,CAAC;AAED,SAAS,gBAAgB,CAAC,OAA4B;IACpD,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,cAAc,CAAC;IAExC,OAAO,IAAI,CAAC,IAAI,KAAK,eAAe,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC;AAChE,CAAC;AAEY,QAAA,mBAAmB,GAAG,mBAAW,CAAC,WAAW,CAAC,WAAW,CACpE;IACE,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,UAAU,CAAC,IAAI;gBACb,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;gBAEhC,IACE,cAAc,CAAC,IAAI,CAAC,IAAI,KAAK,eAAe;oBAC5C,cAAc,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,EACjC,CAAC;oBACD,OAAO;gBACT,CAAC;gBAED,gEAAgE;gBAChE,kEAAkE;gBAClE,IAAI,CAAC,IAAA,uCAAiB,EAAC,cAAc,EAAE,cAAc,CAAC;oBAAE,OAAO;gBAE/D,MAAM,WAAW,GAAG,wBAAwB,CAAC,IAAI,CAAC,CAAC;gBAEnD,IAAI,CAAC,WAAW,IAAI,CAAC,gBAAgB,CAAC,WAAW,CAAC;oBAAE,OAAO;gBAE3D,OAAO,CAAC,MAAM,CAAC;oBACb,IAAI,EAAE,WAAW;oBACjB,SAAS,EAAE,yBAAyB;iBACrC,CAAC,CAAC;YACL,CAAC;SACF,CAAC;IACJ,CAAC;IACD,IAAI,EAAE;QACJ,IAAI,EAAE,SAAS;QACf,IAAI,EAAE;YACJ,WAAW,EAAE,yBAAyB,IAAI,4BAA4B,OAAO,WAAW,cAAc,WAAW;SAClH;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,uBAAuB,EAAE;gBACvB,GAAG,IAAI,kCAAkC,OAAO,eAAe,cAAc,+BAA+B;gBAC5G,iCAAiC,OAAO,yCAAyC;gBACjF,cAAc,OAAO,4CAA4C,cAAc,kBAAkB;aAClG,CAAC,IAAI,CAAC,GAAG,CAAC;SACZ;KACF;IACD,cAAc,EAAE,EAAE;CACnB,CACF,CAAC"}
@@ -10,8 +10,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.TooltipButtonIconWrap = void 0;
11
11
  const utils_1 = require("@typescript-eslint/utils");
12
12
  const has_spread_1 = require("../../utils/has_spread");
13
+ const has_meaningful_attr_1 = require("../../utils/has_meaningful_attr");
13
14
  const BUTTON_ICON = 'EuiButtonIcon';
14
15
  const TOOLTIP = 'EuiToolTip';
16
+ const COPY = 'EuiCopy';
17
+ const BEFORE_MESSAGE = 'beforeMessage';
15
18
  function isWrappedByTooltip(node) {
16
19
  let current = node.parent;
17
20
  while (current) {
@@ -37,6 +40,33 @@ function isWrappedByTooltip(node) {
37
40
  }
38
41
  return false;
39
42
  }
43
+ /**
44
+ * `EuiCopy` renders its render-prop child inside its own `EuiToolTip`, but only
45
+ * when `beforeMessage` is set — that prop is the tooltip's `content`, and
46
+ * `EuiToolTip` suppresses itself when the content is empty. So an
47
+ * `EuiButtonIcon` rendered within an `<EuiCopy beforeMessage="…">` already has a
48
+ * tooltip for sighted users and wrapping it in another `EuiToolTip` would create
49
+ * nested, conflicting tooltips — see the `no-nested-copy-tooltip` rule. Without
50
+ * a meaningful `beforeMessage` there is no such tooltip, so the button must
51
+ * still be wrapped.
52
+ *
53
+ * The exemption only applies to buttons in the render-prop output. If the walk
54
+ * crosses a `JSXAttribute` before reaching the `EuiCopy`, the button lives in a
55
+ * prop value (e.g. `beforeMessage={<EuiButtonIcon />}`) rather than the child
56
+ * `EuiCopy` renders, so it is not covered by the built-in tooltip.
57
+ */
58
+ function isInsideEuiCopyWithBeforeMessage(node) {
59
+ for (let current = node.parent; current; current = current.parent) {
60
+ if (current.type === 'JSXAttribute')
61
+ return false;
62
+ if (current.type === 'JSXElement' &&
63
+ current.openingElement.name.type === 'JSXIdentifier' &&
64
+ current.openingElement.name.name === COPY) {
65
+ return (0, has_meaningful_attr_1.hasMeaningfulAttr)(current.openingElement, BEFORE_MESSAGE);
66
+ }
67
+ }
68
+ return false;
69
+ }
40
70
  exports.TooltipButtonIconWrap = utils_1.ESLintUtils.RuleCreator.withoutDocs({
41
71
  create(context) {
42
72
  return {
@@ -62,6 +92,7 @@ exports.TooltipButtonIconWrap = utils_1.ESLintUtils.RuleCreator.withoutDocs({
62
92
  return;
63
93
  }
64
94
  if (!isWrappedByTooltip(node) &&
95
+ !isInsideEuiCopyWithBeforeMessage(node) &&
65
96
  !(0, has_spread_1.hasSpread)(openingElement.attributes)) {
66
97
  context.report({
67
98
  node: openingElement,
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip_button_icon_wrap.js","sourceRoot":"","sources":["../../../../src/rules/a11y/tooltip_button_icon_wrap.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tooltip_button_icon_wrap.js","sourceRoot":"","sources":["../../../../src/rules/a11y/tooltip_button_icon_wrap.ts"],"names":[],"mappings":"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"}
@@ -10,6 +10,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.TooltipNoInteractiveContent = void 0;
11
11
  const utils_1 = require("@typescript-eslint/utils");
12
12
  const constants_1 = require("../../utils/constants");
13
+ const walk_jsx_children_1 = require("../../utils/walk_jsx_children");
14
+ const get_element_name_1 = require("../../utils/get_element_name");
13
15
  const TOOLTIP_COMPONENTS = ['EuiToolTip', 'EuiIconTip'];
14
16
  const TOOLTIP_CONTENT_PROPS = ['content', 'title'];
15
17
  const INTERACTIVE_HTML_ELEMENTS = [
@@ -24,42 +26,6 @@ const INTERACTIVE_ELEMENTS = new Set([
24
26
  ...INTERACTIVE_HTML_ELEMENTS,
25
27
  ...constants_1.INTERACTIVE_EUI_COMPONENTS.filter((c) => !CONDITIONALLY_INTERACTIVE_SET.has(c)),
26
28
  ]);
27
- function findInteractiveElement(node) {
28
- if (node.type === 'JSXElement') {
29
- const el = node;
30
- const { name } = el.openingElement;
31
- if (name.type === 'JSXIdentifier' && INTERACTIVE_ELEMENTS.has(name.name)) {
32
- return el.openingElement;
33
- }
34
- for (const child of el.children) {
35
- const found = findInteractiveElement(child);
36
- if (found)
37
- return found;
38
- }
39
- }
40
- else if (node.type === 'JSXFragment') {
41
- for (const child of node.children) {
42
- const found = findInteractiveElement(child);
43
- if (found)
44
- return found;
45
- }
46
- }
47
- else if (node.type === 'JSXExpressionContainer') {
48
- const { expression } = node;
49
- if (expression.type !== 'JSXEmptyExpression') {
50
- return findInteractiveElement(expression);
51
- }
52
- }
53
- else if (node.type === 'LogicalExpression') {
54
- const { left, right } = node;
55
- return findInteractiveElement(left) ?? findInteractiveElement(right);
56
- }
57
- else if (node.type === 'ConditionalExpression') {
58
- const { consequent, alternate } = node;
59
- return (findInteractiveElement(consequent) ?? findInteractiveElement(alternate));
60
- }
61
- return null;
62
- }
63
29
  exports.TooltipNoInteractiveContent = utils_1.ESLintUtils.RuleCreator.withoutDocs({
64
30
  create(context) {
65
31
  return {
@@ -83,19 +49,30 @@ exports.TooltipNoInteractiveContent = utils_1.ESLintUtils.RuleCreator.withoutDoc
83
49
  if (expression.type === 'JSXEmptyExpression') {
84
50
  continue;
85
51
  }
86
- const interactiveEl = findInteractiveElement(expression);
87
- if (interactiveEl) {
52
+ let found = false;
53
+ (0, walk_jsx_children_1.walkJsxChildren)(expression, (leaf) => {
54
+ if (found || leaf.type !== 'JSXElement')
55
+ return;
56
+ const el = leaf;
57
+ const name = (0, get_element_name_1.getElementName)(el.openingElement);
58
+ if (!name || !INTERACTIVE_ELEMENTS.has(name))
59
+ return;
88
60
  context.report({
89
- node: interactiveEl,
61
+ node: el.openingElement,
90
62
  messageId: 'noInteractiveContent',
91
63
  data: {
92
64
  propName: attr.name.name,
93
65
  componentName,
94
- elementName: interactiveEl.name
95
- .name,
66
+ elementName: name,
96
67
  },
97
68
  });
98
- }
69
+ found = true;
70
+ }, {
71
+ shouldSkip: (el) => {
72
+ const name = (0, get_element_name_1.getElementName)(el.openingElement);
73
+ return !name || !INTERACTIVE_ELEMENTS.has(name);
74
+ },
75
+ });
99
76
  }
100
77
  },
101
78
  };
@@ -1 +1 @@
1
- {"version":3,"file":"tooltip_no_interactive_content.js","sourceRoot":"","sources":["../../../../src/rules/a11y/tooltip_no_interactive_content.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tooltip_no_interactive_content.js","sourceRoot":"","sources":["../../../../src/rules/a11y/tooltip_no_interactive_content.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { type TSESLint } from '@typescript-eslint/utils';
2
+ export declare const ButtonGroupNoInvalidChildren: TSESLint.RuleModule<"invalidUnresolvableWrapperChild" | "invalidWrapperChild" | "invalidChild" | "invalidUnresolvableChild" | "invalidPopoverButton" | "invalidUnresolvablePopoverButton", [], unknown, TSESLint.RuleListener>;