@hypersolid-dev/eslint-config 1.0.0 → 3.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 +23 -0
- package/README.md +28 -1
- package/dist/base.d.ts +1 -0
- package/dist/base.js +63 -8
- package/dist/plugins/react-native-a11y/constants/accessibility-props.d.ts +32 -0
- package/dist/plugins/react-native-a11y/constants/accessibility-props.js +50 -0
- package/dist/plugins/react-native-a11y/constants/accessibility-state.d.ts +2 -0
- package/dist/plugins/react-native-a11y/constants/accessibility-state.js +8 -0
- package/dist/plugins/react-native-a11y/constants/interactive.d.ts +6 -0
- package/dist/plugins/react-native-a11y/constants/interactive.js +33 -0
- package/dist/plugins/react-native-a11y/constants/react-native-components.d.ts +7 -0
- package/dist/plugins/react-native-a11y/constants/react-native-components.js +13 -0
- package/dist/plugins/react-native-a11y/constants/schema-properties.d.ts +4 -0
- package/dist/plugins/react-native-a11y/constants/schema-properties.js +10 -0
- package/dist/plugins/react-native-a11y/index.d.ts +3 -0
- package/dist/plugins/react-native-a11y/index.js +48 -0
- package/dist/plugins/react-native-a11y/models/optional-options.d.ts +3 -0
- package/dist/plugins/react-native-a11y/models/optional-options.js +1 -0
- package/dist/plugins/react-native-a11y/rules/accessibility-actions-need-handler.d.ts +5 -0
- package/dist/plugins/react-native-a11y/rules/accessibility-actions-need-handler.js +82 -0
- package/dist/plugins/react-native-a11y/rules/accessibility-hint.d.ts +5 -0
- package/dist/plugins/react-native-a11y/rules/accessibility-hint.js +74 -0
- package/dist/plugins/react-native-a11y/rules/accessibility-label.d.ts +6 -0
- package/dist/plugins/react-native-a11y/rules/accessibility-label.js +103 -0
- package/dist/plugins/react-native-a11y/rules/accessibility-role.d.ts +5 -0
- package/dist/plugins/react-native-a11y/rules/accessibility-role.js +72 -0
- package/dist/plugins/react-native-a11y/rules/accessibility-value-needs-range.d.ts +4 -0
- package/dist/plugins/react-native-a11y/rules/accessibility-value-needs-range.js +49 -0
- package/dist/plugins/react-native-a11y/rules/adjustable-needs-value.d.ts +4 -0
- package/dist/plugins/react-native-a11y/rules/adjustable-needs-value.js +40 -0
- package/dist/plugins/react-native-a11y/rules/gate-announce-for-accessibility.d.ts +4 -0
- package/dist/plugins/react-native-a11y/rules/gate-announce-for-accessibility.js +77 -0
- package/dist/plugins/react-native-a11y/rules/input-purpose.d.ts +6 -0
- package/dist/plugins/react-native-a11y/rules/input-purpose.js +84 -0
- package/dist/plugins/react-native-a11y/rules/no-aria-legacy-mix.d.ts +4 -0
- package/dist/plugins/react-native-a11y/rules/no-aria-legacy-mix.js +57 -0
- package/dist/plugins/react-native-a11y/rules/no-deprecated-accessibility-focus.d.ts +4 -0
- package/dist/plugins/react-native-a11y/rules/no-deprecated-accessibility-focus.js +31 -0
- package/dist/plugins/react-native-a11y/rules/no-dropped-aria-on-text.d.ts +5 -0
- package/dist/plugins/react-native-a11y/rules/no-dropped-aria-on-text.js +66 -0
- package/dist/plugins/react-native-a11y/rules/no-font-scaling-disabled.d.ts +5 -0
- package/dist/plugins/react-native-a11y/rules/no-font-scaling-disabled.js +49 -0
- package/dist/plugins/react-native-a11y/rules/no-ineffective-accessibility-props.d.ts +9 -0
- package/dist/plugins/react-native-a11y/rules/no-ineffective-accessibility-props.js +76 -0
- package/dist/plugins/react-native-a11y/rules/no-invalid-accessibility-state.d.ts +5 -0
- package/dist/plugins/react-native-a11y/rules/no-invalid-accessibility-state.js +82 -0
- package/dist/plugins/react-native-a11y/rules/no-nested-focus-stops.d.ts +5 -0
- package/dist/plugins/react-native-a11y/rules/no-nested-focus-stops.js +70 -0
- package/dist/plugins/react-native-a11y/rules/no-press-in-activation.d.ts +5 -0
- package/dist/plugins/react-native-a11y/rules/no-press-in-activation.js +59 -0
- package/dist/plugins/react-native-a11y/rules/no-unnamed-interactive.d.ts +5 -0
- package/dist/plugins/react-native-a11y/rules/no-unnamed-interactive.js +75 -0
- package/dist/plugins/react-native-a11y/rules/require-invert-colors-opt-out.d.ts +5 -0
- package/dist/plugins/react-native-a11y/rules/require-invert-colors-opt-out.js +62 -0
- package/dist/plugins/react-native-a11y/rules/require-modal-a11y-on-sheets.d.ts +5 -0
- package/dist/plugins/react-native-a11y/rules/require-modal-a11y-on-sheets.js +55 -0
- package/dist/plugins/react-native-a11y/utils/create-rule.d.ts +5 -0
- package/dist/plugins/react-native-a11y/utils/create-rule.js +3 -0
- package/dist/plugins/react-native-a11y/utils/get-amount-of-text-children.d.ts +8 -0
- package/dist/plugins/react-native-a11y/utils/get-amount-of-text-children.js +67 -0
- package/dist/plugins/react-native-a11y/utils/get-components.d.ts +7 -0
- package/dist/plugins/react-native-a11y/utils/get-components.js +11 -0
- package/dist/plugins/react-native-a11y/utils/get-element-name.d.ts +10 -0
- package/dist/plugins/react-native-a11y/utils/get-element-name.js +66 -0
- package/dist/plugins/react-native-a11y/utils/get-jsx-descendants.d.ts +4 -0
- package/dist/plugins/react-native-a11y/utils/get-jsx-descendants.js +49 -0
- package/dist/plugins/react-native-a11y/utils/get-literal-property-value.d.ts +7 -0
- package/dist/plugins/react-native-a11y/utils/get-literal-property-value.js +21 -0
- package/dist/plugins/react-native-a11y/utils/get-literal-text-child.d.ts +8 -0
- package/dist/plugins/react-native-a11y/utils/get-literal-text-child.js +40 -0
- package/dist/plugins/react-native-a11y/utils/get-property.d.ts +4 -0
- package/dist/plugins/react-native-a11y/utils/get-property.js +9 -0
- package/dist/plugins/react-native-a11y/utils/has-accessible-name.d.ts +6 -0
- package/dist/plugins/react-native-a11y/utils/has-accessible-name.js +27 -0
- package/dist/plugins/react-native-a11y/utils/has-property.d.ts +3 -0
- package/dist/plugins/react-native-a11y/utils/has-property.js +3 -0
- package/dist/plugins/react-native-a11y/utils/has-spread-props.d.ts +8 -0
- package/dist/plugins/react-native-a11y/utils/has-spread-props.js +8 -0
- package/dist/plugins/react-native-a11y/utils/is-definitely-grouped.d.ts +7 -0
- package/dist/plugins/react-native-a11y/utils/is-definitely-grouped.js +20 -0
- package/dist/plugins/react-native-a11y/utils/is-hidden-from-accessibility.d.ts +19 -0
- package/dist/plugins/react-native-a11y/utils/is-hidden-from-accessibility.js +51 -0
- package/dist/plugins/react-native-a11y/utils/is-inside-focus-stop.d.ts +9 -0
- package/dist/plugins/react-native-a11y/utils/is-inside-focus-stop.js +36 -0
- package/dist/plugins/react-native-a11y/utils/is-interactive.d.ts +16 -0
- package/dist/plugins/react-native-a11y/utils/is-interactive.js +38 -0
- package/dist/plugins/react-native-a11y/utils/is-not-a-focus-stop.d.ts +7 -0
- package/dist/plugins/react-native-a11y/utils/is-not-a-focus-stop.js +19 -0
- package/dist/react-native.js +85 -1
- package/dist/shared.d.ts +8 -0
- package/dist/shared.js +22 -1
- package/package.json +4 -2
package/dist/react-native.js
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
import globals from 'globals';
|
|
2
|
-
import
|
|
2
|
+
import noSecrets from 'eslint-plugin-no-secrets';
|
|
3
|
+
import reactNativeA11y from './plugins/react-native-a11y/index.js';
|
|
4
|
+
import { CODE_FILES, NUMBER_GLOBAL_RESTRICTIONS, raiseWarnings, REACT_BOOLEAN_NAME_OPTIONS, reactConfigs, TEST_FILES, } from './shared.js';
|
|
5
|
+
const A11Y = '@hypersolid-dev/react-native-a11y';
|
|
3
6
|
// Derived instead of hardcoded: the frozen `confusing-browser-globals` list (last released 2021) misses `document`,
|
|
4
7
|
// `localStorage` and `getComputedStyle`, and bans `self`, which React Native defines. `globals` is maintained,
|
|
5
8
|
// so new browser APIs are picked up without editing this file.
|
|
6
9
|
// Globals Hermes provides that `globals['react-native']` does not list yet; remove a name once `globals` adds it.
|
|
7
10
|
const HERMES_GLOBALS = new Set(['atob', 'btoa', 'TextEncoder']);
|
|
8
11
|
const BROWSER_GLOBALS = Object.keys(globals.browser).filter((name) => !(name in globals['react-native']) && !HERMES_GLOBALS.has(name));
|
|
12
|
+
// High-entropy strings in Expo and native config that are identifiers, not credentials.
|
|
13
|
+
const NO_SECRETS_IGNORE = [
|
|
14
|
+
'^android\\.settings\\.', // Android intent actions
|
|
15
|
+
'^EXPO_', // env var names
|
|
16
|
+
'^@xml', // Android resource references
|
|
17
|
+
'^NSPrivacy[A-Za-z]+$', // iOS privacy manifest keys
|
|
18
|
+
'^[A-Z][A-Za-z0-9]*\\/[A-Z][A-Za-z0-9]*$', // i18n `Namespace/Key` paths
|
|
19
|
+
'^data:', // Lottie and embedded images
|
|
20
|
+
];
|
|
9
21
|
export default function reactNative() {
|
|
10
22
|
return raiseWarnings([
|
|
11
23
|
{
|
|
@@ -16,6 +28,7 @@ export default function reactNative() {
|
|
|
16
28
|
{
|
|
17
29
|
name: '@hypersolid-dev/react-native',
|
|
18
30
|
files: CODE_FILES,
|
|
31
|
+
plugins: { 'no-secrets': noSecrets },
|
|
19
32
|
rules: {
|
|
20
33
|
// Browser globals React Native lacks, and the coercing number globals. Bad: `document.title`, `isNaN(value)`.
|
|
21
34
|
'no-restricted-globals': [
|
|
@@ -48,6 +61,77 @@ export default function reactNative() {
|
|
|
48
61
|
'unicorn/prefer-event-target': 'off',
|
|
49
62
|
// Metro emits CommonJS, so top-level await does not bundle. Bad: `await init();` at module scope.
|
|
50
63
|
'unicorn/prefer-top-level-await': 'off',
|
|
64
|
+
// A boolean reads as a claim; Reanimated's `SharedValue<boolean>` is read through `.value`. Bad: `const visible = useSharedValue(true)`.
|
|
65
|
+
'unicorn/consistent-boolean-name': [
|
|
66
|
+
'error',
|
|
67
|
+
{ ...REACT_BOOLEAN_NAME_OPTIONS, wrappers: { SharedValue: 'value' } },
|
|
68
|
+
],
|
|
69
|
+
// High-entropy strings that look like credentials, minus Expo and native identifiers. Bad: `const token = 'ghp_Zx8kQ2vLm9…'`.
|
|
70
|
+
'no-secrets/no-secrets': ['error', { ignoreContent: NO_SECRETS_IGNORE }],
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: '@hypersolid-dev/react-native/json',
|
|
75
|
+
files: ['**/*.json'],
|
|
76
|
+
plugins: { 'no-secrets': noSecrets },
|
|
77
|
+
rules: {
|
|
78
|
+
// Credentials in JSON, minus letters-only words and Expo and native identifiers. Bad: `{ "token": "ghp_Zx8kQ2vLm9…" }`.
|
|
79
|
+
'no-secrets/no-secrets': ['error', { ignoreContent: ['^[A-Za-z]+$', ...NO_SECRETS_IGNORE] }],
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
name: '@hypersolid-dev/react-native/tests',
|
|
84
|
+
files: TEST_FILES,
|
|
85
|
+
rules: {
|
|
86
|
+
// Off: tests stub browser globals. Bad: `document.title = 'x'` in a jsdom test reported.
|
|
87
|
+
'no-restricted-globals': 'off',
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
// React Native accessibility, each rule citing its WCAG criterion. Docs: src/plugins/react-native-a11y/docs.
|
|
92
|
+
name: '@hypersolid-dev/react-native/a11y',
|
|
93
|
+
files: CODE_FILES,
|
|
94
|
+
plugins: { [A11Y]: reactNativeA11y },
|
|
95
|
+
rules: {
|
|
96
|
+
// Custom accessibility actions need an `onAccessibilityAction`. Bad: `<ListItem accessibilityActions={[{ name: 'delete' }]} />`.
|
|
97
|
+
[`${A11Y}/accessibility-actions-need-handler`]: 'error',
|
|
98
|
+
// A hint describes the outcome, never the only name. Bad: `<TouchableOpacity accessibilityHint="Go to the next page"><Icon /></TouchableOpacity>`.
|
|
99
|
+
[`${A11Y}/accessibility-hint`]: 'error',
|
|
100
|
+
// Controls without visible text need a label, and a label contains any visible text. Bad: `<Pressable onPress={onPress}><Icon /></Pressable>`.
|
|
101
|
+
[`${A11Y}/accessibility-label`]: 'error',
|
|
102
|
+
// Interactive elements declare a role. Bad: `<Pressable onPress={onPress} />`.
|
|
103
|
+
[`${A11Y}/accessibility-role`]: 'error',
|
|
104
|
+
// A numeric `accessibilityValue` needs `min` and `max`. Bad: `<View accessibilityRole="adjustable" accessibilityValue={{ now: 5 }} />`.
|
|
105
|
+
[`${A11Y}/accessibility-value-needs-range`]: 'error',
|
|
106
|
+
// An adjustable element announces its value. Bad: `<View accessibilityRole="adjustable" />`.
|
|
107
|
+
[`${A11Y}/adjustable-needs-value`]: 'error',
|
|
108
|
+
// `announceForAccessibility` next to an Android live region needs a `Platform.OS` check, or TalkBack hears it twice. Bad: an unguarded `AccessibilityInfo.announceForAccessibility(message)` in a file with `accessibilityLiveRegion`.
|
|
109
|
+
[`${A11Y}/gate-announce-for-accessibility`]: 'error',
|
|
110
|
+
// Inputs declare their autofill purpose with `autoComplete`, which covers both platforms. Bad: `<TextInput textContentType="emailAddress" />`.
|
|
111
|
+
[`${A11Y}/input-purpose`]: 'error',
|
|
112
|
+
// Don't set both the ARIA and the legacy spelling of a prop. Bad: `<Pressable role="button" accessibilityRole="button" />`.
|
|
113
|
+
[`${A11Y}/no-aria-legacy-mix`]: 'error',
|
|
114
|
+
// `setAccessibilityFocus` is deprecated in favour of `sendAccessibilityEvent`. Bad: `AccessibilityInfo.setAccessibilityFocus(findNodeHandle(ref.current))`.
|
|
115
|
+
[`${A11Y}/no-deprecated-accessibility-focus`]: 'error',
|
|
116
|
+
// `Text` silently drops some ARIA props. Bad: `<Text aria-live="polite">{status}</Text>`.
|
|
117
|
+
[`${A11Y}/no-dropped-aria-on-text`]: 'error',
|
|
118
|
+
// Text keeps scaling with the user's font size. Bad: `allowFontScaling={false}` on a `Text`.
|
|
119
|
+
[`${A11Y}/no-font-scaling-disabled`]: 'error',
|
|
120
|
+
// Accessibility props on an element that never becomes an accessibility element do nothing. Bad: `<View role="listitem" />`.
|
|
121
|
+
[`${A11Y}/no-ineffective-accessibility-props`]: 'error',
|
|
122
|
+
// A state object built outside the JSX holds only supported keys. Bad: `const state = { invalid: true }; <Pressable accessibilityState={state} />`.
|
|
123
|
+
[`${A11Y}/no-invalid-accessibility-state`]: 'error',
|
|
124
|
+
// A focus stop inside another one is unreachable for screen readers. Bad: `<View accessible accessibilityLabel="Card"><Pressable accessibilityLabel="Save" /></View>`.
|
|
125
|
+
[`${A11Y}/no-nested-focus-stops`]: 'error',
|
|
126
|
+
// Activate on release so a press can be cancelled. Bad: `<Pressable accessibilityLabel="Save" onPressIn={submit} />`.
|
|
127
|
+
[`${A11Y}/no-press-in-activation`]: 'error',
|
|
128
|
+
// An element made accessible needs a name. Bad: `<View accessible accessibilityRole="button" />`.
|
|
129
|
+
[`${A11Y}/no-unnamed-interactive`]: 'error',
|
|
130
|
+
// Images opt out of iOS Smart Invert or render as a negative. Bad: `<Image source={source} accessibilityLabel="A cat" />`.
|
|
131
|
+
[`${A11Y}/require-invert-colors-opt-out`]: 'error',
|
|
132
|
+
// Off: a sheet is whatever a project calls one, so the rule has no defaults. Enable it with the project's sheet components:
|
|
133
|
+
// `['error', { additionalComponents: ['BottomSheet'] }]`. Bad then: `<BottomSheet><Text>Body</Text></BottomSheet>`.
|
|
134
|
+
[`${A11Y}/require-modal-a11y-on-sheets`]: 'off',
|
|
51
135
|
},
|
|
52
136
|
},
|
|
53
137
|
]);
|
package/dist/shared.d.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { Linter } from 'eslint';
|
|
2
2
|
export declare const CODE_FILES: string[];
|
|
3
|
+
export declare const TEST_FILES: string[];
|
|
4
|
+
export declare const BOOLEAN_NAME_OPTIONS: {
|
|
5
|
+
checkFunctions: string;
|
|
6
|
+
};
|
|
7
|
+
export declare const REACT_BOOLEAN_NAME_OPTIONS: {
|
|
8
|
+
ignore: string[];
|
|
9
|
+
checkFunctions: string;
|
|
10
|
+
};
|
|
3
11
|
export declare const NUMBER_GLOBAL_RESTRICTIONS: {
|
|
4
12
|
name: string;
|
|
5
13
|
message: string;
|
package/dist/shared.js
CHANGED
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
import eslintReact from '@eslint-react/eslint-plugin';
|
|
2
2
|
import reactHooks from 'eslint-plugin-react-hooks';
|
|
3
|
+
import unicorn from 'eslint-plugin-unicorn';
|
|
3
4
|
import hypersolid from './plugins/props-destructuring.js';
|
|
4
5
|
export const CODE_FILES = ['**/*.{js,mjs,cjs,jsx,ts,mts,cts,tsx}'];
|
|
6
|
+
// Tests, stories, mocks and test setup: each preset relaxes a few rules here that test doubles break by design.
|
|
7
|
+
export const TEST_FILES = [
|
|
8
|
+
'**/*.{test,spec,stories}.{js,mjs,cjs,jsx,ts,mts,cts,tsx}',
|
|
9
|
+
'**/__mocks__/**',
|
|
10
|
+
'**/{jest,vitest}.setup.*',
|
|
11
|
+
];
|
|
12
|
+
// `unicorn/consistent-boolean-name` options per preset; a later config replaces options, so each preset states them all.
|
|
13
|
+
export const BOOLEAN_NAME_OPTIONS = { checkFunctions: 'never' };
|
|
14
|
+
// Hooks (`useIsOpen`) and jest mock factories (`mockIsReady`) are named by convention, not as claims.
|
|
15
|
+
export const REACT_BOOLEAN_NAME_OPTIONS = { ...BOOLEAN_NAME_OPTIONS, ignore: ['^use[A-Z]', '^mock'] };
|
|
5
16
|
// Shared by every preset that sets `no-restricted-globals`: a later config replaces the rule's options, not merges them.
|
|
6
17
|
export const NUMBER_GLOBAL_RESTRICTIONS = ['isFinite', 'isNaN'].map((name) => ({
|
|
7
18
|
name,
|
|
@@ -39,7 +50,7 @@ export function reactConfigs() {
|
|
|
39
50
|
{
|
|
40
51
|
name: '@hypersolid-dev/react',
|
|
41
52
|
files: CODE_FILES,
|
|
42
|
-
plugins: { '@hypersolid-dev': hypersolid },
|
|
53
|
+
plugins: { '@hypersolid-dev': hypersolid, unicorn },
|
|
43
54
|
languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } },
|
|
44
55
|
rules: {
|
|
45
56
|
// Off: react-hooks/exhaustive-deps reports it. Bad: `useEffect(() => log(id), [])` reported twice.
|
|
@@ -72,6 +83,16 @@ export function reactConfigs() {
|
|
|
72
83
|
'@eslint-react/no-unstable-context-value': 'error',
|
|
73
84
|
// Props are readable from the component's signature; a union props type may keep `props`. Bad: `const Card = (props: Props) => <h1>{props.title}</h1>`.
|
|
74
85
|
'@hypersolid-dev/props-destructuring': 'error',
|
|
86
|
+
// A boolean reads as a claim; hook and mock names are exempt. Bad: `const visible = true` (use `isVisible`).
|
|
87
|
+
'unicorn/consistent-boolean-name': ['error', REACT_BOOLEAN_NAME_OPTIONS],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
name: '@hypersolid-dev/react/tests',
|
|
92
|
+
files: TEST_FILES,
|
|
93
|
+
rules: {
|
|
94
|
+
// Off: a mocked hook keeps the `use` name of the hook it replaces. Bad: `const useUser = () => fakeUser` in a mock.
|
|
95
|
+
'@eslint-react/no-unnecessary-use-prefix': 'off',
|
|
75
96
|
},
|
|
76
97
|
},
|
|
77
98
|
];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hypersolid-dev/eslint-config",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Shared ESLint flat config for Hypersolid TypeScript projects",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"scripts": {
|
|
49
49
|
"build": "tsc -p tsconfig.build.json",
|
|
50
50
|
"lint": "pnpm build && eslint .",
|
|
51
|
-
"test": "pnpm build && node --test 'test/*.test.ts'",
|
|
51
|
+
"test": "pnpm build && node --test 'test/*.test.ts' 'test/rules/**/*.test.ts'",
|
|
52
52
|
"prepublishOnly": "pnpm test"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
@@ -70,6 +70,8 @@
|
|
|
70
70
|
"@eslint/js": "^10.0.1",
|
|
71
71
|
"@eslint/json": "^2.1.1",
|
|
72
72
|
"@next/eslint-plugin-next": "^16.4.3",
|
|
73
|
+
"@typescript-eslint/types": "^8.72.1",
|
|
74
|
+
"@typescript-eslint/utils": "^8.72.1",
|
|
73
75
|
"eslint-import-resolver-typescript": "^4.4.5",
|
|
74
76
|
"eslint-plugin-import-x": "^4.17.1",
|
|
75
77
|
"eslint-plugin-jsx-a11y": "^6.10.2",
|