@hypersolid-dev/eslint-config 5.0.0 → 7.0.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/CHANGELOG.md +39 -0
- package/README.md +37 -21
- package/dist/base.js +19 -6
- package/dist/jest.d.ts +3 -0
- package/dist/jest.js +56 -0
- package/dist/plugins/{hypersolid.d.ts → base/index.d.ts} +1 -0
- package/dist/plugins/base/index.js +15 -0
- package/dist/plugins/{rules → base/rules}/comment-style.js +45 -36
- package/dist/plugins/{rules → base/rules}/regex-pattern-const.js +2 -2
- package/dist/plugins/{rules → base/rules}/undefined-check.js +4 -4
- package/dist/plugins/react/index.d.ts +4 -0
- package/dist/plugins/react/index.js +23 -0
- package/dist/plugins/{rules → react/rules}/boolean-guard.js +5 -5
- package/dist/plugins/{rules → react/rules}/effect-takes-callback.js +2 -2
- package/dist/plugins/{rules → react/rules}/jsdoc-for-props.js +3 -3
- package/dist/plugins/{rules → react/rules}/no-callback-payload.js +20 -17
- package/dist/plugins/{rules → react/rules}/no-markup-variable.js +43 -37
- package/dist/plugins/{rules → react/rules}/no-unnecessary-use-callback.js +3 -3
- package/dist/plugins/react/rules/props-destructuring.d.ts +3 -0
- package/dist/plugins/{props-destructuring.js → react/rules/props-destructuring.js} +13 -17
- package/dist/plugins/{react-native-a11y → react-native/a11y}/index.js +1 -1
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/accessibility-actions-need-handler.js +3 -3
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/accessibility-hint.js +3 -3
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/accessibility-label.js +3 -3
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/accessibility-role.js +3 -3
- package/dist/plugins/react-native/a11y/rules/accessibility-value-needs-range.js +47 -0
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/adjustable-needs-value.js +17 -19
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/gate-announce-for-accessibility.js +5 -5
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/input-purpose.js +3 -3
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-aria-legacy-mix.js +21 -23
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-deprecated-accessibility-focus.js +13 -15
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-dropped-aria-on-text.js +3 -3
- package/dist/plugins/react-native/a11y/rules/no-font-scaling-disabled.js +47 -0
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-ineffective-accessibility-props.js +35 -37
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-invalid-accessibility-state.js +32 -34
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-nested-focus-stops.js +3 -3
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-press-in-activation.js +3 -3
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-unnamed-interactive.js +3 -3
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/require-invert-colors-opt-out.js +3 -3
- package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/require-modal-a11y-on-sheets.js +3 -3
- package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/get-amount-of-text-children.js +15 -13
- package/dist/plugins/{props-destructuring.d.ts → react-native/index.d.ts} +1 -0
- package/dist/plugins/react-native/index.js +17 -0
- package/dist/plugins/{rules → react-native/rules}/test-id-default.js +24 -28
- package/dist/plugins/{rules → react-native/rules}/test-id-format.js +16 -20
- package/dist/plugins/{rules → react-native/rules}/test-id-from-props.js +25 -29
- package/dist/plugins/{rules → react-native/rules}/webview-allow-list.js +24 -28
- package/dist/plugins/{utils → shared}/expressions.d.ts +3 -3
- package/dist/plugins/{utils → shared}/expressions.js +94 -78
- package/dist/plugins/{utils → shared}/types.js +14 -12
- package/dist/react-native.js +37 -8
- package/dist/shared.d.ts +3 -3
- package/dist/shared.js +169 -113
- package/package.json +12 -2
- package/dist/plugins/hypersolid.js +0 -38
- package/dist/plugins/react-native-a11y/rules/accessibility-value-needs-range.js +0 -49
- package/dist/plugins/react-native-a11y/rules/no-font-scaling-disabled.js +0 -49
- package/dist/plugins/react-native-a11y/utils/create-rule.js +0 -3
- package/dist/plugins/utils/create-rule.d.ts +0 -5
- /package/dist/plugins/{rules → base/rules}/comment-style.d.ts +0 -0
- /package/dist/plugins/{rules → base/rules}/regex-pattern-const.d.ts +0 -0
- /package/dist/plugins/{rules → base/rules}/undefined-check.d.ts +0 -0
- /package/dist/plugins/{rules → react/rules}/boolean-guard.d.ts +0 -0
- /package/dist/plugins/{rules → react/rules}/effect-takes-callback.d.ts +0 -0
- /package/dist/plugins/{rules → react/rules}/jsdoc-for-props.d.ts +0 -0
- /package/dist/plugins/{rules → react/rules}/no-callback-payload.d.ts +0 -0
- /package/dist/plugins/{rules → react/rules}/no-markup-variable.d.ts +0 -0
- /package/dist/plugins/{rules → react/rules}/no-unnecessary-use-callback.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/constants/accessibility-props.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/constants/accessibility-props.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/constants/accessibility-state.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/constants/accessibility-state.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/constants/interactive.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/constants/interactive.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/constants/react-native-components.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/constants/react-native-components.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/constants/schema-properties.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/constants/schema-properties.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/index.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/models/optional-options.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/models/optional-options.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/accessibility-actions-need-handler.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/accessibility-hint.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/accessibility-label.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/accessibility-role.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/accessibility-value-needs-range.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/adjustable-needs-value.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/gate-announce-for-accessibility.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/input-purpose.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-aria-legacy-mix.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-deprecated-accessibility-focus.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-dropped-aria-on-text.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-font-scaling-disabled.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-ineffective-accessibility-props.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-invalid-accessibility-state.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-nested-focus-stops.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-press-in-activation.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/no-unnamed-interactive.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/require-invert-colors-opt-out.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/require-modal-a11y-on-sheets.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/get-amount-of-text-children.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/get-components.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/get-components.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/get-element-name.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/get-element-name.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/get-jsx-descendants.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/get-jsx-descendants.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/get-literal-property-value.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/get-literal-property-value.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/get-literal-text-child.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/get-literal-text-child.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/get-property.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/get-property.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/has-accessible-name.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/has-accessible-name.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/has-property.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/has-property.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/has-spread-props.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/has-spread-props.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/is-definitely-grouped.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/is-definitely-grouped.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/is-hidden-from-accessibility.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/is-hidden-from-accessibility.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/is-inside-focus-stop.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/is-inside-focus-stop.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/is-interactive.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/is-interactive.js +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/is-not-a-focus-stop.d.ts +0 -0
- /package/dist/plugins/{react-native-a11y → react-native/a11y}/utils/is-not-a-focus-stop.js +0 -0
- /package/dist/plugins/{rules → react-native/rules}/test-id-default.d.ts +0 -0
- /package/dist/plugins/{rules → react-native/rules}/test-id-format.d.ts +0 -0
- /package/dist/plugins/{rules → react-native/rules}/test-id-from-props.d.ts +0 -0
- /package/dist/plugins/{rules → react-native/rules}/webview-allow-list.d.ts +0 -0
- /package/dist/plugins/{utils → shared}/comments.d.ts +0 -0
- /package/dist/plugins/{utils → shared}/comments.js +0 -0
- /package/dist/plugins/{utils → shared}/component-name.d.ts +0 -0
- /package/dist/plugins/{utils → shared}/component-name.js +0 -0
- /package/dist/plugins/{react-native-a11y/utils → shared}/create-rule.d.ts +0 -0
- /package/dist/plugins/{utils → shared}/create-rule.js +0 -0
- /package/dist/plugins/{utils → shared}/types.d.ts +0 -0
|
@@ -1,7 +1,19 @@
|
|
|
1
1
|
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
2
|
-
import createRule from "
|
|
3
|
-
import { componentName, isWrapperCall } from "
|
|
2
|
+
import createRule from "../../shared/create-rule.js";
|
|
3
|
+
import { componentName, isWrapperCall } from "../../shared/component-name.js";
|
|
4
4
|
const CALLBACK_PATTERN = /^on[A-Z]/;
|
|
5
|
+
/** Adds each identifier an object pattern binds to `props`, and its rest binding to `objects` too. */
|
|
6
|
+
const addPatternBindings = (pattern, props, objects) => {
|
|
7
|
+
for (const property of pattern.properties) {
|
|
8
|
+
const value = property.type === AST_NODE_TYPES.RestElement ? property.argument : property.value;
|
|
9
|
+
const binding = value.type === AST_NODE_TYPES.AssignmentPattern ? value.left : value;
|
|
10
|
+
if (binding.type !== AST_NODE_TYPES.Identifier)
|
|
11
|
+
continue;
|
|
12
|
+
props.add(binding);
|
|
13
|
+
if (property.type === AST_NODE_TYPES.RestElement)
|
|
14
|
+
objects.add(binding);
|
|
15
|
+
}
|
|
16
|
+
};
|
|
5
17
|
/** The first parameter's bindings: each prop it destructures, and the props object itself or a rest of it. */
|
|
6
18
|
const propertyBindings = (parameter) => {
|
|
7
19
|
const props = new Set();
|
|
@@ -11,17 +23,8 @@ const propertyBindings = (parameter) => {
|
|
|
11
23
|
props.add(target);
|
|
12
24
|
objects.add(target);
|
|
13
25
|
}
|
|
14
|
-
if (target?.type === AST_NODE_TYPES.ObjectPattern)
|
|
15
|
-
|
|
16
|
-
const value = property.type === AST_NODE_TYPES.RestElement ? property.argument : property.value;
|
|
17
|
-
const binding = value.type === AST_NODE_TYPES.AssignmentPattern ? value.left : value;
|
|
18
|
-
if (binding.type !== AST_NODE_TYPES.Identifier)
|
|
19
|
-
continue;
|
|
20
|
-
props.add(binding);
|
|
21
|
-
if (property.type === AST_NODE_TYPES.RestElement)
|
|
22
|
-
objects.add(binding);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
26
|
+
if (target?.type === AST_NODE_TYPES.ObjectPattern)
|
|
27
|
+
addPatternBindings(target, props, objects);
|
|
25
28
|
return { props, objects };
|
|
26
29
|
};
|
|
27
30
|
/**
|
|
@@ -53,7 +56,7 @@ const noCallbackPayload = createRule({
|
|
|
53
56
|
payload: "`{{ callback }}` is called with values `{{ component }}` only received from its parent. Let the parent bind them where it passes `{{ callback }}`, and call it with what this component itself knows (or nothing), so the component stays free of the payload's domain shape.",
|
|
54
57
|
},
|
|
55
58
|
},
|
|
56
|
-
create(context) {
|
|
59
|
+
create: (context) => {
|
|
57
60
|
const { sourceCode } = context;
|
|
58
61
|
const exported = new Set();
|
|
59
62
|
const pending = [];
|
|
@@ -173,7 +176,7 @@ const noCallbackPayload = createRule({
|
|
|
173
176
|
ArrowFunctionExpression: check,
|
|
174
177
|
FunctionDeclaration: check,
|
|
175
178
|
FunctionExpression: check,
|
|
176
|
-
ExportDefaultDeclaration(node) {
|
|
179
|
+
ExportDefaultDeclaration: (node) => {
|
|
177
180
|
// `export default memo(Row)` exports `Row`, however many wrappers it is under.
|
|
178
181
|
let declaration = node.declaration;
|
|
179
182
|
while (isWrapperCall(declaration))
|
|
@@ -187,7 +190,7 @@ const noCallbackPayload = createRule({
|
|
|
187
190
|
exported.add(declaration.id.name);
|
|
188
191
|
}
|
|
189
192
|
},
|
|
190
|
-
ExportNamedDeclaration(node) {
|
|
193
|
+
ExportNamedDeclaration: (node) => {
|
|
191
194
|
for (const specifier of node.specifiers) {
|
|
192
195
|
if (specifier.local.type === AST_NODE_TYPES.Identifier)
|
|
193
196
|
exported.add(specifier.local.name);
|
|
@@ -202,7 +205,7 @@ const noCallbackPayload = createRule({
|
|
|
202
205
|
}
|
|
203
206
|
}
|
|
204
207
|
},
|
|
205
|
-
"Program:exit"() {
|
|
208
|
+
"Program:exit": () => {
|
|
206
209
|
for (const { node, data } of pending) {
|
|
207
210
|
if (exported.has(data.component))
|
|
208
211
|
context.report({ node, messageId: "payload", data });
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
2
|
-
import createRule from "
|
|
3
|
-
import { componentName } from "
|
|
2
|
+
import createRule from "../../shared/create-rule.js";
|
|
3
|
+
import { componentName } from "../../shared/component-name.js";
|
|
4
4
|
/** The JSX a declarator's value draws: itself, or a branch of a ternary or `&&`. */
|
|
5
5
|
const drawnJsx = (init) => {
|
|
6
6
|
if (!init)
|
|
@@ -63,7 +63,45 @@ const noMarkupVariable = createRule({
|
|
|
63
63
|
inline: "`{{ name }}` holds JSX that `{{ component }}` reads only once. Write it where it is rendered.",
|
|
64
64
|
},
|
|
65
65
|
},
|
|
66
|
-
create(context) {
|
|
66
|
+
create: (context) => {
|
|
67
|
+
/** Read once, never reassigned, and that read is a JSX child rather than an attribute value. */
|
|
68
|
+
const isRenderedOnceInline = (declarator) => {
|
|
69
|
+
const variable = context.sourceCode.getDeclaredVariables(declarator).at(0);
|
|
70
|
+
const references = variable?.references ?? [];
|
|
71
|
+
const reads = references.filter((ref) => ref.isRead());
|
|
72
|
+
const isReassigned = references.some((ref) => ref.isWrite() && ref.identifier !== declarator.id);
|
|
73
|
+
const container = reads.at(0)?.identifier.parent;
|
|
74
|
+
return (reads.length === 1 &&
|
|
75
|
+
!isReassigned &&
|
|
76
|
+
container?.type === AST_NODE_TYPES.JSXExpressionContainer &&
|
|
77
|
+
container.parent.type !== AST_NODE_TYPES.JSXAttribute);
|
|
78
|
+
};
|
|
79
|
+
const checkDeclarator = (declarator, component) => {
|
|
80
|
+
if (declarator.id.type !== AST_NODE_TYPES.Identifier)
|
|
81
|
+
return;
|
|
82
|
+
const jsx = drawnJsx(declarator.init);
|
|
83
|
+
if (jsx.length === 0)
|
|
84
|
+
return;
|
|
85
|
+
if (jsx.some(hasStyledElement)) {
|
|
86
|
+
context.report({
|
|
87
|
+
node: declarator.id,
|
|
88
|
+
messageId: "extract",
|
|
89
|
+
data: {
|
|
90
|
+
name: declarator.id.name,
|
|
91
|
+
component,
|
|
92
|
+
suggestion: `${component}${toComponentName(declarator.id.name)}`,
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (isRenderedOnceInline(declarator)) {
|
|
98
|
+
context.report({
|
|
99
|
+
node: declarator.id,
|
|
100
|
+
messageId: "inline",
|
|
101
|
+
data: { name: declarator.id.name, component },
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
};
|
|
67
105
|
const check = (fn) => {
|
|
68
106
|
const component = componentName(fn);
|
|
69
107
|
if (!component || fn.body.type !== AST_NODE_TYPES.BlockStatement)
|
|
@@ -71,40 +109,8 @@ const noMarkupVariable = createRule({
|
|
|
71
109
|
for (const statement of fn.body.body) {
|
|
72
110
|
if (statement.type !== AST_NODE_TYPES.VariableDeclaration)
|
|
73
111
|
continue;
|
|
74
|
-
for (const declarator of statement.declarations)
|
|
75
|
-
|
|
76
|
-
continue;
|
|
77
|
-
const jsx = drawnJsx(declarator.init);
|
|
78
|
-
if (jsx.length === 0)
|
|
79
|
-
continue;
|
|
80
|
-
if (!jsx.some(hasStyledElement)) {
|
|
81
|
-
const variable = context.sourceCode.getDeclaredVariables(declarator).at(0);
|
|
82
|
-
const references = variable?.references ?? [];
|
|
83
|
-
const reads = references.filter((ref) => ref.isRead());
|
|
84
|
-
const isReassigned = references.some((ref) => ref.isWrite() && ref.identifier !== declarator.id);
|
|
85
|
-
const container = reads.at(0)?.identifier.parent;
|
|
86
|
-
if (reads.length === 1 &&
|
|
87
|
-
!isReassigned &&
|
|
88
|
-
container?.type === AST_NODE_TYPES.JSXExpressionContainer &&
|
|
89
|
-
container.parent.type !== AST_NODE_TYPES.JSXAttribute) {
|
|
90
|
-
context.report({
|
|
91
|
-
node: declarator.id,
|
|
92
|
-
messageId: "inline",
|
|
93
|
-
data: { name: declarator.id.name, component },
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
context.report({
|
|
99
|
-
node: declarator.id,
|
|
100
|
-
messageId: "extract",
|
|
101
|
-
data: {
|
|
102
|
-
name: declarator.id.name,
|
|
103
|
-
component,
|
|
104
|
-
suggestion: `${component}${toComponentName(declarator.id.name)}`,
|
|
105
|
-
},
|
|
106
|
-
});
|
|
107
|
-
}
|
|
112
|
+
for (const declarator of statement.declarations)
|
|
113
|
+
checkDeclarator(declarator, component);
|
|
108
114
|
}
|
|
109
115
|
};
|
|
110
116
|
return {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AST_NODE_TYPES, TSESLint } from "@typescript-eslint/utils";
|
|
2
|
-
import createRule from "
|
|
2
|
+
import createRule from "../../shared/create-rule.js";
|
|
3
3
|
const HAZARD_NAMES = new Set(["arguments", "eval"]);
|
|
4
4
|
/** The import specifier a name resolves to, when it is a value import from `react`. */
|
|
5
5
|
const reactImport = (sourceCode, identifier) => {
|
|
@@ -84,10 +84,10 @@ const noUnnecessaryUseCallback = createRule({
|
|
|
84
84
|
unnecessary: "This callback captures no render-local values. Use an existing function or define it at module scope, unless a proven per-instance identity contract requires memoization; explain that contract in a scoped suppression.",
|
|
85
85
|
},
|
|
86
86
|
},
|
|
87
|
-
create(context) {
|
|
87
|
+
create: (context) => {
|
|
88
88
|
const { sourceCode } = context;
|
|
89
89
|
return {
|
|
90
|
-
CallExpression(node) {
|
|
90
|
+
CallExpression: (node) => {
|
|
91
91
|
if (!isUseCallback(sourceCode, node.callee))
|
|
92
92
|
return;
|
|
93
93
|
const [callback, dependencies] = [node.arguments.at(0), node.arguments.at(1)];
|
|
@@ -3,7 +3,7 @@ const WRAPPERS = new Set(['memo', 'forwardRef']);
|
|
|
3
3
|
const isFunction = (node) => typeof node === 'object' && node !== null && FUNCTION_TYPES.has(node.type);
|
|
4
4
|
const PASCAL_CASE_PATTERN = /^[A-Z]/;
|
|
5
5
|
const isPascalCase = (name) => typeof name === 'string' && PASCAL_CASE_PATTERN.test(name);
|
|
6
|
-
|
|
6
|
+
const isJsx = (node) => {
|
|
7
7
|
if (typeof node !== 'object' || node === null) {
|
|
8
8
|
return false;
|
|
9
9
|
}
|
|
@@ -15,22 +15,22 @@ function isJsx(node) {
|
|
|
15
15
|
return isJsx(consequent) || isJsx(alternate);
|
|
16
16
|
}
|
|
17
17
|
return type === 'LogicalExpression' && (isJsx(left) || isJsx(right));
|
|
18
|
-
}
|
|
18
|
+
};
|
|
19
19
|
// Searches the function's own return statements; nested functions return for themselves.
|
|
20
|
-
|
|
20
|
+
const isReturningJsx = (node) => {
|
|
21
21
|
if (typeof node !== 'object' || node === null) {
|
|
22
22
|
return false;
|
|
23
23
|
}
|
|
24
24
|
if (Array.isArray(node)) {
|
|
25
|
-
return node.some(
|
|
25
|
+
return node.some(isReturningJsx);
|
|
26
26
|
}
|
|
27
27
|
const current = node;
|
|
28
28
|
return current.type === 'ReturnStatement'
|
|
29
29
|
? isJsx(current.argument)
|
|
30
|
-
: Object.entries(current).some(([key, value]) => key !== 'parent' && !isFunction(value) && typeof value === 'object' &&
|
|
31
|
-
}
|
|
30
|
+
: Object.entries(current).some(([key, value]) => key !== 'parent' && !isFunction(value) && typeof value === 'object' && isReturningJsx(value));
|
|
31
|
+
};
|
|
32
32
|
// `memo(fn)`, `React.forwardRef(fn)` and `memo(forwardRef(fn))`.
|
|
33
|
-
|
|
33
|
+
const unwrap = (node) => {
|
|
34
34
|
if (isFunction(node)) {
|
|
35
35
|
return node;
|
|
36
36
|
}
|
|
@@ -41,7 +41,7 @@ function unwrap(node) {
|
|
|
41
41
|
const { type: calleeType, name, property } = callee;
|
|
42
42
|
const calleeName = calleeType === 'MemberExpression' ? property.name : name;
|
|
43
43
|
return typeof calleeName === 'string' && WRAPPERS.has(calleeName) ? unwrap(args[0]) : undefined;
|
|
44
|
-
}
|
|
44
|
+
};
|
|
45
45
|
const propsDestructuring = {
|
|
46
46
|
meta: {
|
|
47
47
|
type: 'suggestion',
|
|
@@ -51,7 +51,7 @@ const propsDestructuring = {
|
|
|
51
51
|
destructure: 'Destructure the props in the signature: `({ title }: Props)`. A discriminated-union props type may keep `props`.',
|
|
52
52
|
},
|
|
53
53
|
},
|
|
54
|
-
create(context) {
|
|
54
|
+
create: (context) => {
|
|
55
55
|
const services = context.sourceCode.parserServices;
|
|
56
56
|
const checker = services.program?.getTypeChecker();
|
|
57
57
|
// Destructuring a union in the signature breaks narrowing (`if (props.kind === 'a') props.aOnly`).
|
|
@@ -61,18 +61,18 @@ const propsDestructuring = {
|
|
|
61
61
|
};
|
|
62
62
|
const check = (fn) => {
|
|
63
63
|
const props = fn?.params[0];
|
|
64
|
-
if (!fn || props?.type !== 'Identifier' || !
|
|
64
|
+
if (!fn || props?.type !== 'Identifier' || !isReturningJsx(fn.body) && !isJsx(fn.body) || isUnion(props)) {
|
|
65
65
|
return;
|
|
66
66
|
}
|
|
67
67
|
context.report({ node: props, messageId: 'destructure' });
|
|
68
68
|
};
|
|
69
69
|
return {
|
|
70
|
-
FunctionDeclaration(node) {
|
|
70
|
+
FunctionDeclaration: (node) => {
|
|
71
71
|
if (isPascalCase(node.id.name)) {
|
|
72
72
|
check(node);
|
|
73
73
|
}
|
|
74
74
|
},
|
|
75
|
-
VariableDeclarator(node) {
|
|
75
|
+
VariableDeclarator: (node) => {
|
|
76
76
|
if (node.id.type === 'Identifier' && isPascalCase(node.id.name)) {
|
|
77
77
|
check(unwrap(node.init));
|
|
78
78
|
}
|
|
@@ -80,8 +80,4 @@ const propsDestructuring = {
|
|
|
80
80
|
};
|
|
81
81
|
},
|
|
82
82
|
};
|
|
83
|
-
|
|
84
|
-
meta: { name: '@hypersolid-dev/eslint-config' },
|
|
85
|
-
rules: { 'props-destructuring': propsDestructuring },
|
|
86
|
-
};
|
|
87
|
-
export default plugin;
|
|
83
|
+
export default propsDestructuring;
|
|
@@ -43,7 +43,7 @@ const rules = {
|
|
|
43
43
|
* before Triple became Hypersolid. Rule docs live in ./docs.
|
|
44
44
|
*/
|
|
45
45
|
const plugin = {
|
|
46
|
-
meta: { name: "@hypersolid-dev/react-native
|
|
46
|
+
meta: { name: "@hypersolid-dev/react-native/a11y" },
|
|
47
47
|
rules,
|
|
48
48
|
};
|
|
49
49
|
// typescript-eslint rule types are stricter than ESLint's `Plugin` type and not assignable to it; the runtime shape is the same.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
2
|
-
import createRule from "
|
|
2
|
+
import createRule from "../../../shared/create-rule.js";
|
|
3
3
|
import getProperty from "../utils/get-property.js";
|
|
4
4
|
import hasSpreadProps from "../utils/has-spread-props.js";
|
|
5
5
|
/** Names the platforms already describe to the user. */
|
|
@@ -26,7 +26,7 @@ const accessibilityActionsNeedHandler = createRule({
|
|
|
26
26
|
},
|
|
27
27
|
schema: [],
|
|
28
28
|
},
|
|
29
|
-
create(context) {
|
|
29
|
+
create: (context) => {
|
|
30
30
|
const reportUnlabelledActions = (expression) => {
|
|
31
31
|
if (expression.type !== AST_NODE_TYPES.ArrayExpression) {
|
|
32
32
|
return;
|
|
@@ -54,7 +54,7 @@ const accessibilityActionsNeedHandler = createRule({
|
|
|
54
54
|
}
|
|
55
55
|
};
|
|
56
56
|
return {
|
|
57
|
-
JSXOpeningElement(node) {
|
|
57
|
+
JSXOpeningElement: (node) => {
|
|
58
58
|
if (hasSpreadProps(node)) {
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TOUCHABLES } from "../constants/react-native-components.js";
|
|
2
2
|
import schemaProperties from "../constants/schema-properties.js";
|
|
3
|
-
import createRule from "
|
|
3
|
+
import createRule from "../../../shared/create-rule.js";
|
|
4
4
|
import getAmountOfTextChildren from "../utils/get-amount-of-text-children.js";
|
|
5
5
|
import getComponents from "../utils/get-components.js";
|
|
6
6
|
import getElementName from "../utils/get-element-name.js";
|
|
@@ -33,13 +33,13 @@ const accessibilityHint = createRule({
|
|
|
33
33
|
},
|
|
34
34
|
],
|
|
35
35
|
},
|
|
36
|
-
create(context) {
|
|
36
|
+
create: (context) => {
|
|
37
37
|
const components = getComponents({
|
|
38
38
|
context,
|
|
39
39
|
defaultComponents: TOUCHABLES,
|
|
40
40
|
});
|
|
41
41
|
return {
|
|
42
|
-
JSXOpeningElement(node) {
|
|
42
|
+
JSXOpeningElement: (node) => {
|
|
43
43
|
const componentName = getElementName(node);
|
|
44
44
|
if (componentName === undefined) {
|
|
45
45
|
return;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IMAGES, INPUTS, TOUCHABLES } from "../constants/react-native-components.js";
|
|
2
2
|
import schemaProperties from "../constants/schema-properties.js";
|
|
3
|
-
import createRule from "
|
|
3
|
+
import createRule from "../../../shared/create-rule.js";
|
|
4
4
|
import getAmountOfTextChildren from "../utils/get-amount-of-text-children.js";
|
|
5
5
|
import getComponents from "../utils/get-components.js";
|
|
6
6
|
import getElementName from "../utils/get-element-name.js";
|
|
@@ -35,13 +35,13 @@ const accessibilityLabel = createRule({
|
|
|
35
35
|
},
|
|
36
36
|
],
|
|
37
37
|
},
|
|
38
|
-
create(context) {
|
|
38
|
+
create: (context) => {
|
|
39
39
|
const components = getComponents({
|
|
40
40
|
context,
|
|
41
41
|
defaultComponents: [...IMAGES, ...TOUCHABLES, ...INPUTS],
|
|
42
42
|
});
|
|
43
43
|
return {
|
|
44
|
-
JSXOpeningElement(node) {
|
|
44
|
+
JSXOpeningElement: (node) => {
|
|
45
45
|
const componentName = getElementName(node);
|
|
46
46
|
if (componentName === undefined) {
|
|
47
47
|
return;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { IMAGES, TOUCHABLES } from "../constants/react-native-components.js";
|
|
2
2
|
import schemaProperties from "../constants/schema-properties.js";
|
|
3
|
-
import createRule from "
|
|
3
|
+
import createRule from "../../../shared/create-rule.js";
|
|
4
4
|
import getComponents from "../utils/get-components.js";
|
|
5
5
|
import getElementName from "../utils/get-element-name.js";
|
|
6
6
|
import hasProperty from "../utils/has-property.js";
|
|
@@ -31,13 +31,13 @@ const accessibilityRole = createRule({
|
|
|
31
31
|
},
|
|
32
32
|
],
|
|
33
33
|
},
|
|
34
|
-
create(context) {
|
|
34
|
+
create: (context) => {
|
|
35
35
|
const components = getComponents({
|
|
36
36
|
context,
|
|
37
37
|
defaultComponents: [...TOUCHABLES, ...IMAGES],
|
|
38
38
|
});
|
|
39
39
|
return {
|
|
40
|
-
JSXOpeningElement(node) {
|
|
40
|
+
JSXOpeningElement: (node) => {
|
|
41
41
|
const componentName = getElementName(node);
|
|
42
42
|
if (componentName === undefined) {
|
|
43
43
|
return;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
2
|
+
import createRule from "../../../shared/create-rule.js";
|
|
3
|
+
import getProperty from "../utils/get-property.js";
|
|
4
|
+
const keysOf = (expression) => expression.properties.flatMap((property) => property.type === AST_NODE_TYPES.Property &&
|
|
5
|
+
property.key.type === AST_NODE_TYPES.Identifier
|
|
6
|
+
? [property.key.name]
|
|
7
|
+
: []);
|
|
8
|
+
const accessibilityValueNeedsRange = createRule({
|
|
9
|
+
name: "accessibility-value-needs-range",
|
|
10
|
+
meta: {
|
|
11
|
+
defaultOptions: [],
|
|
12
|
+
type: "problem",
|
|
13
|
+
docs: {
|
|
14
|
+
description: "Enforce accessibilityValue carries a range, so a current value means something.",
|
|
15
|
+
},
|
|
16
|
+
messages: {
|
|
17
|
+
valueWithoutRange: "'accessibilityValue' sets a current value with no scale to read it against, so assistive tech announces a bare number. Add 'min' and 'max', or a 'text' that says the value in words.",
|
|
18
|
+
},
|
|
19
|
+
schema: [],
|
|
20
|
+
},
|
|
21
|
+
create: (context) => ({
|
|
22
|
+
JSXOpeningElement: (node) => {
|
|
23
|
+
const attribute = getProperty(node, "accessibilityValue");
|
|
24
|
+
if (attribute?.value?.type !== AST_NODE_TYPES.JSXExpressionContainer) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
const { expression } = attribute.value;
|
|
28
|
+
// A value built elsewhere cannot be read here
|
|
29
|
+
if (expression.type !== AST_NODE_TYPES.ObjectExpression) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// A spread may carry the range, and cannot be read from here
|
|
33
|
+
if (expression.properties.some((property) => property.type === AST_NODE_TYPES.SpreadElement)) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const keys = keysOf(expression);
|
|
37
|
+
if (!keys.includes("now") || keys.includes("text")) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (keys.includes("min") && keys.includes("max")) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
context.report({ node: attribute, messageId: "valueWithoutRange" });
|
|
44
|
+
},
|
|
45
|
+
}),
|
|
46
|
+
});
|
|
47
|
+
export default accessibilityValueNeedsRange;
|
package/dist/plugins/{react-native-a11y → react-native/a11y}/rules/adjustable-needs-value.js
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { VALUE_ALIAS_KEYS } from "../constants/accessibility-props.js";
|
|
2
|
-
import createRule from "
|
|
2
|
+
import createRule from "../../../shared/create-rule.js";
|
|
3
3
|
import getLiteralPropertyValue from "../utils/get-literal-property-value.js";
|
|
4
4
|
import hasProperty from "../utils/has-property.js";
|
|
5
5
|
import hasSpreadProps from "../utils/has-spread-props.js";
|
|
@@ -18,23 +18,21 @@ const adjustableNeedsValue = createRule({
|
|
|
18
18
|
},
|
|
19
19
|
schema: [],
|
|
20
20
|
},
|
|
21
|
-
create(context) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
};
|
|
38
|
-
},
|
|
21
|
+
create: (context) => ({
|
|
22
|
+
JSXOpeningElement: (node) => {
|
|
23
|
+
const role = getLiteralPropertyValue(node, ["accessibilityRole", "role"]);
|
|
24
|
+
if (typeof role !== "string" || !ROLES_NEEDING_VALUE.has(role)) {
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (hasSpreadProps(node) || hasProperty(node, VALUE_PROPS)) {
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
context.report({
|
|
31
|
+
node,
|
|
32
|
+
messageId: "missingAccessibilityValue",
|
|
33
|
+
data: { role },
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
}),
|
|
39
37
|
});
|
|
40
38
|
export default adjustableNeedsValue;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
2
|
-
import createRule from "
|
|
2
|
+
import createRule from "../../../shared/create-rule.js";
|
|
3
3
|
import getProperty from "../utils/get-property.js";
|
|
4
4
|
const LIVE_REGION_PROPS = ["accessibilityLiveRegion", "aria-live"];
|
|
5
5
|
const FUNCTION_TYPES = new Set([
|
|
@@ -28,7 +28,7 @@ const gateAnnounceForAccessibility = createRule({
|
|
|
28
28
|
},
|
|
29
29
|
schema: [],
|
|
30
30
|
},
|
|
31
|
-
create(context) {
|
|
31
|
+
create: (context) => {
|
|
32
32
|
/**
|
|
33
33
|
* A bare announce is the legitimate cross-platform pattern. The double
|
|
34
34
|
* announcement only happens where a live region covers Android already, so
|
|
@@ -38,12 +38,12 @@ const gateAnnounceForAccessibility = createRule({
|
|
|
38
38
|
const announces = [];
|
|
39
39
|
const platformChecks = [];
|
|
40
40
|
return {
|
|
41
|
-
JSXOpeningElement(node) {
|
|
41
|
+
JSXOpeningElement: (node) => {
|
|
42
42
|
if (getProperty(node, LIVE_REGION_PROPS)) {
|
|
43
43
|
hasLiveRegion = true;
|
|
44
44
|
}
|
|
45
45
|
},
|
|
46
|
-
MemberExpression(node) {
|
|
46
|
+
MemberExpression: (node) => {
|
|
47
47
|
if (node.property.type !== AST_NODE_TYPES.Identifier) {
|
|
48
48
|
return;
|
|
49
49
|
}
|
|
@@ -58,7 +58,7 @@ const gateAnnounceForAccessibility = createRule({
|
|
|
58
58
|
platformChecks.push(node);
|
|
59
59
|
}
|
|
60
60
|
},
|
|
61
|
-
"Program:exit"() {
|
|
61
|
+
"Program:exit": () => {
|
|
62
62
|
if (!hasLiveRegion) {
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TEXT_INPUTS } from "../constants/react-native-components.js";
|
|
2
2
|
import schemaProperties from "../constants/schema-properties.js";
|
|
3
|
-
import createRule from "
|
|
3
|
+
import createRule from "../../../shared/create-rule.js";
|
|
4
4
|
import getComponents from "../utils/get-components.js";
|
|
5
5
|
import getElementName from "../utils/get-element-name.js";
|
|
6
6
|
import getLiteralPropertyValue from "../utils/get-literal-property-value.js";
|
|
@@ -42,13 +42,13 @@ const inputPurpose = createRule({
|
|
|
42
42
|
},
|
|
43
43
|
],
|
|
44
44
|
},
|
|
45
|
-
create(context) {
|
|
45
|
+
create: (context) => {
|
|
46
46
|
const components = getComponents({
|
|
47
47
|
context,
|
|
48
48
|
defaultComponents: TEXT_INPUTS,
|
|
49
49
|
});
|
|
50
50
|
return {
|
|
51
|
-
JSXOpeningElement(node) {
|
|
51
|
+
JSXOpeningElement: (node) => {
|
|
52
52
|
const componentName = getElementName(node);
|
|
53
53
|
if (componentName === undefined) {
|
|
54
54
|
return;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
2
2
|
import { ALIAS_TO_LEGACY, STATE_ALIAS_KEYS, VALUE_ALIAS_KEYS, } from "../constants/accessibility-props.js";
|
|
3
|
-
import createRule from "
|
|
3
|
+
import createRule from "../../../shared/create-rule.js";
|
|
4
4
|
import getProperty from "../utils/get-property.js";
|
|
5
5
|
/**
|
|
6
6
|
* Both spellings map to the same native behaviour and only one of them reaches
|
|
@@ -30,28 +30,26 @@ const noAriaLegacyMix = createRule({
|
|
|
30
30
|
},
|
|
31
31
|
schema: [],
|
|
32
32
|
},
|
|
33
|
-
create(context) {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
continue;
|
|
39
|
-
}
|
|
40
|
-
const stateKey = STATE_ALIAS_KEYS[alias] ?? VALUE_ALIAS_KEYS[alias];
|
|
41
|
-
// A grouped prop only clashes on the key the alias maps onto
|
|
42
|
-
const isClashes = stateKey
|
|
43
|
-
? hasStateKey(node, legacy, stateKey)
|
|
44
|
-
: getProperty(node, legacy) !== undefined;
|
|
45
|
-
if (isClashes) {
|
|
46
|
-
context.report({
|
|
47
|
-
node,
|
|
48
|
-
messageId: "ariaLegacyMix",
|
|
49
|
-
data: { alias, legacy },
|
|
50
|
-
});
|
|
51
|
-
}
|
|
33
|
+
create: (context) => ({
|
|
34
|
+
JSXOpeningElement: (node) => {
|
|
35
|
+
for (const [alias, legacy] of Object.entries(ALIAS_TO_LEGACY)) {
|
|
36
|
+
if (!getProperty(node, alias)) {
|
|
37
|
+
continue;
|
|
52
38
|
}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
39
|
+
const stateKey = STATE_ALIAS_KEYS[alias] ?? VALUE_ALIAS_KEYS[alias];
|
|
40
|
+
// A grouped prop only clashes on the key the alias maps onto
|
|
41
|
+
const isClashes = stateKey
|
|
42
|
+
? hasStateKey(node, legacy, stateKey)
|
|
43
|
+
: getProperty(node, legacy) !== undefined;
|
|
44
|
+
if (isClashes) {
|
|
45
|
+
context.report({
|
|
46
|
+
node,
|
|
47
|
+
messageId: "ariaLegacyMix",
|
|
48
|
+
data: { alias, legacy },
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
},
|
|
53
|
+
}),
|
|
56
54
|
});
|
|
57
55
|
export default noAriaLegacyMix;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AST_NODE_TYPES } from "@typescript-eslint/utils";
|
|
2
|
-
import createRule from "
|
|
2
|
+
import createRule from "../../../shared/create-rule.js";
|
|
3
3
|
const noDeprecatedAccessibilityFocus = createRule({
|
|
4
4
|
name: "no-deprecated-accessibility-focus",
|
|
5
5
|
meta: {
|
|
@@ -13,19 +13,17 @@ const noDeprecatedAccessibilityFocus = createRule({
|
|
|
13
13
|
},
|
|
14
14
|
schema: [],
|
|
15
15
|
},
|
|
16
|
-
create(context) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
};
|
|
29
|
-
},
|
|
16
|
+
create: (context) => ({
|
|
17
|
+
// Matched on the property so an aliased import is caught too
|
|
18
|
+
MemberExpression: (node) => {
|
|
19
|
+
if (node.property.type === AST_NODE_TYPES.Identifier &&
|
|
20
|
+
node.property.name === "setAccessibilityFocus") {
|
|
21
|
+
context.report({
|
|
22
|
+
node,
|
|
23
|
+
messageId: "deprecatedSetAccessibilityFocus",
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
}),
|
|
30
28
|
});
|
|
31
29
|
export default noDeprecatedAccessibilityFocus;
|