forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1// @ts-check
2import js from '@eslint/js'
3import tseslint from 'typescript-eslint'
4import { defineConfig } from 'eslint/config';
5import react from 'eslint-plugin-react'
6import reactHooks from 'eslint-plugin-react-hooks'
7// @ts-expect-error no types
8import reactNative from 'eslint-plugin-react-native'
9// @ts-expect-error no types
10import reactNativeA11y from 'eslint-plugin-react-native-a11y'
11import simpleImportSort from 'eslint-plugin-simple-import-sort'
12import importX from 'eslint-plugin-import-x'
13import lingui from 'eslint-plugin-lingui'
14import reactCompiler from 'eslint-plugin-react-compiler'
15import bskyInternal from 'eslint-plugin-bsky-internal'
16import globals from 'globals'
17import tsParser from '@typescript-eslint/parser'
18
19export default defineConfig(
20 /**
21 * Global ignores
22 */
23 {
24 ignores: [
25 '**/__mocks__/*.ts',
26 'ios/**',
27 'android/**',
28 'coverage/**',
29 '*.lock',
30 '.husky/**',
31 'patches/**',
32 '*.html',
33 'bskyweb/**',
34 'bskyembed/**',
35 'src/locale/locales/_build/**',
36 'src/locale/locales/**/*.js',
37 '*.e2e.ts',
38 '*.e2e.tsx',
39 'eslint.config.mjs',
40 '.jscodeshift/**',
41 ],
42 },
43
44 /**
45 * Base configurations
46 */
47 js.configs.recommended,
48 tseslint.configs.recommendedTypeChecked,
49 reactHooks.configs.flat.recommended,
50 importX.flatConfigs.recommended,
51 importX.flatConfigs.typescript,
52 importX.flatConfigs['react-native'],
53
54 /**
55 * Main configuration for all JS/TS/JSX/TSX files
56 */
57 {
58 files: ['**/*.{js,jsx,ts,tsx}'],
59 plugins: {
60 react,
61 'react-native': reactNative,
62 'react-native-a11y': reactNativeA11y,
63 'simple-import-sort': simpleImportSort,
64 // @ts-expect-error - not sure why
65 lingui,
66 'react-compiler': reactCompiler,
67 'bsky-internal': bskyInternal,
68 },
69 languageOptions: {
70 ecmaVersion: 'latest',
71 sourceType: 'module',
72 globals: {
73 ...globals.browser,
74 ...globals.node,
75 },
76 parserOptions: {
77 parser: tsParser,
78 projectService: true,
79 tsconfigRootDir: import.meta.dirname,
80 ecmaFeatures: {
81 jsx: true,
82 },
83 },
84 },
85 settings: {
86 react: {
87 version: 'detect',
88 },
89 componentWrapperFunctions: ['observer'],
90 },
91 rules: {
92 /**
93 * Custom rules
94 */
95 'bsky-internal/avoid-unwrapped-text': [
96 'error',
97 {
98 impliedTextComponents: [
99 'H1',
100 'H2',
101 'H3',
102 'H4',
103 'H5',
104 'H6',
105 'P',
106 'Admonition',
107 'Admonition.Admonition',
108 'Toast.Action',
109 'AgeAssuranceAdmonition',
110 'Span',
111 'StackedButton',
112 ],
113 impliedTextProps: [],
114 suggestedTextWrappers: {
115 Button: 'ButtonText',
116 'ToggleButton.Button': 'ToggleButton.ButtonText',
117 'SegmentedControl.Item': 'SegmentedControl.ItemText',
118 },
119 },
120 ],
121 'bsky-internal/use-exact-imports': 'error',
122 'bsky-internal/use-prefixed-imports': 'error',
123 'bsky-internal/lingui-msg-rule': 'error',
124
125 /**
126 * React & React Native
127 */
128 ...react.configs.recommended.rules,
129 ...react.configs['jsx-runtime'].rules,
130 'react/hook-use-state': 'warn',
131 'react/no-unescaped-entities': 'off',
132 'react/prop-types': 'off',
133 'react-native/no-inline-styles': 'off',
134 ...reactNativeA11y.configs.all.rules,
135 'react-compiler/react-compiler': 'warn',
136 // TODO: Fix these and set to error
137 'react-hooks/set-state-in-effect': 'warn',
138 'react-hooks/purity': 'warn',
139 'react-hooks/refs': 'warn',
140 'react-hooks/immutability': 'warn',
141
142 /**
143 * Import sorting
144 */
145 'simple-import-sort/imports': [
146 'error',
147 {
148 groups: [
149 // Side effect imports.
150 ['^\\u0000'],
151 // Node.js builtins prefixed with `node:`.
152 ['^node:'],
153 // Packages.
154 // Things that start with a letter (or digit or underscore), or `@` followed by a letter.
155 // React/React Native prioritized, followed by expo
156 // Followed by all packages excluding unprefixed relative ones
157 [
158 '^(react\\/(.*)$)|^(react$)|^(react-native(.*)$)',
159 '^(expo(.*)$)|^(expo$)',
160 '^(?!(?:alf|components|lib|locale|logger|platform|screens|state|view)(?:$|\\/))@?\\w',
161 ],
162 // Relative imports.
163 // Ideally, anything that starts with a dot or #
164 // due to unprefixed relative imports being used, we whitelist the relative paths we use
165 // (?:$|\\/) matches end of string or /
166 [
167 '^(?:#\\/)?(?:lib|state|logger|platform|locale)(?:$|\\/)',
168 '^(?:#\\/)?view(?:$|\\/)',
169 '^(?:#\\/)?screens(?:$|\\/)',
170 '^(?:#\\/)?alf(?:$|\\/)',
171 '^(?:#\\/)?components(?:$|\\/)',
172 '^#\\/',
173 '^\\.',
174 ],
175 // anything else - hopefully we don't have any of these
176 ['^'],
177 ],
178 },
179 ],
180 'simple-import-sort/exports': 'error',
181
182 /**
183 * Import linting
184 */
185 'import-x/consistent-type-specifier-style': ['warn', 'prefer-inline'],
186 'import-x/no-unresolved': ['error', {
187 /*
188 * The `postinstall` hook runs `compile-if-needed` locally, but not in
189 * CI. For CI-sake, ignore this.
190 */
191 ignore: ['^#\/locale\/locales\/.+\/messages'],
192 }],
193 'import-x/no-extraneous-dependencies': ['error', {
194 'whitelist': [
195 // test files only
196 '@jest/globals',
197 // we only use a really simple util from this, and we know it will be present
198 'expo-modules-core',
199 // this is a dep for @atproto/api, but we absolutely need them in sync, so just
200 // rely on the transient version
201 '@atproto/common-web',
202 ]
203 }],
204 'import-x/no-nodejs-modules': 'error',
205
206 /**
207 * TypeScript-specific rules
208 */
209 'no-unused-vars': 'off', // off, we use TS-specific rule below
210 '@typescript-eslint/no-unused-vars': [
211 'error',
212 {
213 argsIgnorePattern: '^_',
214 varsIgnorePattern: '^_.+',
215 caughtErrors: 'none',
216 ignoreRestSiblings: true,
217 },
218 ],
219 '@typescript-eslint/consistent-type-imports': [
220 'warn',
221 {prefer: 'type-imports', fixStyle: 'inline-type-imports'},
222 ],
223 '@typescript-eslint/no-require-imports': 'off',
224 '@typescript-eslint/no-unused-expressions': ['error', {
225 allowTernary: true,
226 }],
227 /**
228 * Maintain previous behavior - these are stricter in typescript-eslint
229 * v8 `warn` ones are probably worth fixing. `off` ones are a bit too
230 * nit-picky
231 */
232 '@typescript-eslint/no-explicit-any': 'off',
233 '@typescript-eslint/ban-ts-comment': 'off',
234 '@typescript-eslint/no-empty-object-type': 'off',
235 '@typescript-eslint/no-unsafe-function-type': 'off',
236 '@typescript-eslint/no-unsafe-assignment': 'off',
237 '@typescript-eslint/unbound-method': 'off',
238 '@typescript-eslint/no-unsafe-argument': 'off',
239 '@typescript-eslint/no-unsafe-return': 'off',
240 '@typescript-eslint/no-unsafe-member-access': 'warn',
241 '@typescript-eslint/no-unsafe-call': 'warn',
242 '@typescript-eslint/no-floating-promises': 'warn',
243 '@typescript-eslint/no-misused-promises': 'warn',
244 '@typescript-eslint/require-await': 'warn',
245 '@typescript-eslint/no-unsafe-enum-comparison': 'warn',
246 '@typescript-eslint/no-unnecessary-type-assertion': 'warn',
247 '@typescript-eslint/no-redundant-type-constituents': 'warn',
248 '@typescript-eslint/no-duplicate-type-constituents': 'warn',
249 '@typescript-eslint/no-base-to-string': 'warn',
250 '@typescript-eslint/prefer-promise-reject-errors': 'warn',
251 '@typescript-eslint/await-thenable': 'warn',
252
253 /**
254 * Turn off rules that we haven't enforced thus far
255 */
256 'no-empty-pattern': 'off',
257 'no-async-promise-executor': 'off',
258 'no-constant-binary-expression': 'warn',
259 'prefer-const': 'off',
260 'no-empty': 'off',
261 'no-unsafe-optional-chaining': 'off',
262 'no-prototype-builtins': 'off',
263 'no-var': 'off',
264 'prefer-rest-params': 'off',
265 'no-case-declarations': 'off',
266 'no-irregular-whitespace': 'off',
267 'no-useless-escape': 'off',
268 'no-sparse-arrays': 'off',
269 'no-fallthrough': 'off',
270 'no-control-regex': 'off',
271 },
272 },
273
274 /**
275 * Test files configuration
276 */
277 {
278 files: ['**/__tests__/**/*.{js,jsx,ts,tsx}', '**/*.test.{js,jsx,ts,tsx}'],
279 languageOptions: {
280 globals: {
281 ...globals.jest,
282 }
283 },
284 },
285)