@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.
- package/README.md +125 -0
- package/lib/cjs/index.js +10 -1
- package/lib/cjs/rules/a11y/no_nested_copy_tooltip.d.ts +3 -0
- package/lib/cjs/rules/a11y/no_nested_copy_tooltip.d.ts.map +1 -0
- package/lib/cjs/rules/a11y/no_nested_copy_tooltip.js +84 -0
- package/lib/cjs/rules/a11y/tooltip_button_icon_wrap.d.ts.map +1 -1
- package/lib/cjs/rules/a11y/tooltip_button_icon_wrap.js +29 -1
- package/lib/cjs/rules/a11y/tooltip_no_interactive_content.d.ts.map +1 -1
- package/lib/cjs/rules/a11y/tooltip_no_interactive_content.js +17 -45
- package/lib/cjs/rules/button_group_no_invalid_children.d.ts +3 -0
- package/lib/cjs/rules/button_group_no_invalid_children.d.ts.map +1 -0
- package/lib/cjs/rules/button_group_no_invalid_children.js +159 -0
- package/lib/cjs/rules/callout_prefer_props_for_content.d.ts.map +1 -1
- package/lib/cjs/rules/callout_prefer_props_for_content.js +93 -156
- package/lib/cjs/rules/no_deprecated_icon_aliases.d.ts +174 -0
- package/lib/cjs/rules/no_deprecated_icon_aliases.d.ts.map +1 -0
- package/lib/cjs/rules/no_deprecated_icon_aliases.js +302 -0
- package/lib/cjs/utils/flat_map.d.ts +2 -0
- package/lib/cjs/utils/flat_map.d.ts.map +1 -0
- package/lib/cjs/utils/flat_map.js +24 -0
- package/lib/cjs/utils/has_meaningful_attr.d.ts +20 -0
- package/lib/cjs/utils/has_meaningful_attr.d.ts.map +1 -0
- package/lib/cjs/utils/has_meaningful_attr.js +61 -0
- package/lib/cjs/utils/is_fragment.d.ts +8 -0
- package/lib/cjs/utils/is_fragment.d.ts.map +1 -0
- package/lib/cjs/utils/is_fragment.js +26 -0
- package/lib/cjs/utils/walk_jsx_children.d.ts +30 -0
- package/lib/cjs/utils/walk_jsx_children.d.ts.map +1 -0
- package/lib/cjs/utils/walk_jsx_children.js +210 -0
- package/lib/esm/index.js +9 -0
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/rules/a11y/no_nested_copy_tooltip.d.ts +2 -0
- package/lib/esm/rules/a11y/no_nested_copy_tooltip.js +84 -0
- package/lib/esm/rules/a11y/no_nested_copy_tooltip.js.map +1 -0
- package/lib/esm/rules/a11y/tooltip_button_icon_wrap.js +31 -0
- package/lib/esm/rules/a11y/tooltip_button_icon_wrap.js.map +1 -1
- package/lib/esm/rules/a11y/tooltip_no_interactive_content.js +19 -42
- package/lib/esm/rules/a11y/tooltip_no_interactive_content.js.map +1 -1
- package/lib/esm/rules/button_group_no_invalid_children.d.ts +2 -0
- package/lib/esm/rules/button_group_no_invalid_children.js +198 -0
- package/lib/esm/rules/button_group_no_invalid_children.js.map +1 -0
- package/lib/esm/rules/callout_prefer_props_for_content.js +75 -112
- package/lib/esm/rules/callout_prefer_props_for_content.js.map +1 -1
- package/lib/esm/rules/no_deprecated_icon_aliases.d.ts +173 -0
- package/lib/esm/rules/no_deprecated_icon_aliases.js +307 -0
- package/lib/esm/rules/no_deprecated_icon_aliases.js.map +1 -0
- package/lib/esm/utils/flat_map.d.ts +1 -0
- package/lib/esm/utils/flat_map.js +22 -0
- package/lib/esm/utils/flat_map.js.map +1 -0
- package/lib/esm/utils/has_meaningful_attr.d.ts +19 -0
- package/lib/esm/utils/has_meaningful_attr.js +55 -0
- package/lib/esm/utils/has_meaningful_attr.js.map +1 -0
- package/lib/esm/utils/is_fragment.d.ts +7 -0
- package/lib/esm/utils/is_fragment.js +26 -0
- package/lib/esm/utils/is_fragment.js.map +1 -0
- package/lib/esm/utils/walk_jsx_children.d.ts +29 -0
- package/lib/esm/utils/walk_jsx_children.js +213 -0
- package/lib/esm/utils/walk_jsx_children.js.map +1 -0
- 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',
|
package/lib/esm/index.js.map
CHANGED
|
@@ -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;
|
|
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,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":";AAAA;;;;;;GAMG;;;AAEH,oDAAsE;AACtE,uDAAmD;
|
|
1
|
+
{"version":3,"file":"tooltip_button_icon_wrap.js","sourceRoot":"","sources":["../../../../src/rules/a11y/tooltip_button_icon_wrap.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAEH,oDAAsE;AACtE,uDAAmD;AACnD,yEAAoE;AAEpE,MAAM,WAAW,GAAG,eAAe,CAAC;AACpC,MAAM,OAAO,GAAG,YAAY,CAAC;AAC7B,MAAM,IAAI,GAAG,SAAS,CAAC;AACvB,MAAM,cAAc,GAAG,eAAe,CAAC;AAEvC,SAAS,kBAAkB,CAAC,IAAyB;IACnD,IAAI,OAAO,GAAqC,IAAI,CAAC,MAAM,CAAC;IAE5D,OAAO,OAAO,EAAE,CAAC;QACf,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACrB,KAAK,YAAY,CAAC,CAAC,CAAC;gBAClB,MAAM,EAAE,GAAG,OAA8B,CAAC;gBAC1C,IACE,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,KAAK,eAAe;oBAC/C,EAAE,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO,EACvC,CAAC;oBACD,OAAO,IAAI,CAAC;gBACd,CAAC;gBACD,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;gBACzB,MAAM;YACR,CAAC;YACD,KAAK,aAAa,CAAC;YACnB,KAAK,wBAAwB,CAAC;YAC9B,KAAK,mBAAmB,CAAC;YACzB,KAAK,uBAAuB;gBAC1B,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC;gBACzB,MAAM;YACR;gBACE,OAAO,KAAK,CAAC;QACjB,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,SAAS,gCAAgC,CAAC,IAAyB;IACjE,KACE,IAAI,OAAO,GAAqC,IAAI,CAAC,MAAM,EAC3D,OAAO,EACP,OAAO,GAAG,OAAO,CAAC,MAAM,EACxB,CAAC;QACD,IAAI,OAAO,CAAC,IAAI,KAAK,cAAc;YAAE,OAAO,KAAK,CAAC;QAElD,IACE,OAAO,CAAC,IAAI,KAAK,YAAY;YAC7B,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,KAAK,eAAe;YACpD,OAAO,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,EACzC,CAAC;YACD,OAAO,IAAA,uCAAiB,EAAC,OAAO,CAAC,cAAc,EAAE,cAAc,CAAC,CAAC;QACnE,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAEY,QAAA,qBAAqB,GAAG,mBAAW,CAAC,WAAW,CAAC,WAAW,CAAC;IACvE,MAAM,CAAC,OAAO;QACZ,OAAO;YACL,UAAU,CAAC,IAAI;gBACb,MAAM,EAAE,cAAc,EAAE,GAAG,IAAI,CAAC;gBAChC,IACE,cAAc,CAAC,IAAI,CAAC,IAAI,KAAK,eAAe;oBAC5C,cAAc,CAAC,IAAI,CAAC,IAAI,KAAK,WAAW,EACxC,CAAC;oBACD,OAAO;gBACT,CAAC;gBAED,IAAI,SAA4C,CAAC;gBAEjD,KAAK,MAAM,IAAI,IAAI,cAAc,CAAC,UAAU,EAAE,CAAC;oBAC7C,IACE,IAAI,CAAC,IAAI,KAAK,cAAc;wBAC5B,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,eAAe;wBAElC,SAAS;oBACX,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,OAAO;wBAAE,SAAS,GAAG,IAAI,CAAC;gBACnD,CAAC;gBAED,IAAI,SAAS,EAAE,CAAC;oBACd,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI,EAAE,cAAc;wBACpB,SAAS,EAAE,6BAA6B;qBACzC,CAAC,CAAC;oBAEH,OAAO;gBACT,CAAC;gBAED,IACE,CAAC,kBAAkB,CAAC,IAAI,CAAC;oBACzB,CAAC,gCAAgC,CAAC,IAAI,CAAC;oBACvC,CAAC,IAAA,sBAAS,EAAC,cAAc,CAAC,UAAU,CAAC,EACrC,CAAC;oBACD,OAAO,CAAC,MAAM,CAAC;wBACb,IAAI,EAAE,cAAc;wBACpB,SAAS,EAAE,oBAAoB;qBAChC,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;SACF,CAAC;IACJ,CAAC;IACD,IAAI,EAAE;QACJ,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE;YACJ,WAAW,EAAE,UAAU,WAAW,oBAAoB,OAAO,oBAAoB;SAClF;QACD,MAAM,EAAE,EAAE;QACV,QAAQ,EAAE;YACR,2BAA2B,EAAE;gBAC3B,kCAAkC,WAAW,YAAY,OAAO,WAAW;gBAC3E,8FAA8F;gBAC9F,cAAc,OAAO,8DAA8D;gBACnF,kFAAkF;aACnF,CAAC,IAAI,CAAC,GAAG,CAAC;YACX,kBAAkB,EAAE;gBAClB,GAAG,WAAW,4CAA4C;gBAC1D,cAAc,OAAO,qEAAqE;gBAC1F,kFAAkF;aACnF,CAAC,IAAI,CAAC,GAAG,CAAC;SACZ;KACF;IACD,cAAc,EAAE,EAAE;CACnB,CAAC,CAAC"}
|
|
@@ -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
|
-
|
|
87
|
-
|
|
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:
|
|
61
|
+
node: el.openingElement,
|
|
90
62
|
messageId: 'noInteractiveContent',
|
|
91
63
|
data: {
|
|
92
64
|
propName: attr.name.name,
|
|
93
65
|
componentName,
|
|
94
|
-
elementName:
|
|
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":";AAAA;;;;;;GAMG;;;AAEH,oDAAsE;AACtE,qDAG+B;
|
|
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>;
|