Migrate to Oxlint (#10384)
Co-authored-by: DS Boyce <260543580+ds-boyce@users.noreply.github.com>
This commit is contained in:
+2
-2
@@ -108,8 +108,8 @@ google-services.json
|
|||||||
# Performance results (Flashlight)
|
# Performance results (Flashlight)
|
||||||
.perf/
|
.perf/
|
||||||
|
|
||||||
# ESLint
|
# Oxlint
|
||||||
.eslintcache
|
.oxlintcache
|
||||||
|
|
||||||
# i18n
|
# i18n
|
||||||
src/locale/locales/_build/
|
src/locale/locales/_build/
|
||||||
|
|||||||
+407
@@ -0,0 +1,407 @@
|
|||||||
|
{
|
||||||
|
"$schema": "./node_modules/oxlint/configuration_schema.json",
|
||||||
|
"plugins": [
|
||||||
|
"typescript",
|
||||||
|
"react",
|
||||||
|
"import"
|
||||||
|
],
|
||||||
|
"categories": {
|
||||||
|
"correctness": "off"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"typeAware": true
|
||||||
|
},
|
||||||
|
"env": {
|
||||||
|
"builtin": true
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"import-x/extensions": [
|
||||||
|
".ts",
|
||||||
|
".tsx",
|
||||||
|
".cts",
|
||||||
|
".mts",
|
||||||
|
".js",
|
||||||
|
".jsx",
|
||||||
|
".cjs",
|
||||||
|
".mjs"
|
||||||
|
],
|
||||||
|
"import-x/external-module-folders": [
|
||||||
|
"node_modules",
|
||||||
|
"node_modules/@types"
|
||||||
|
],
|
||||||
|
"import-x/parsers": {
|
||||||
|
"@typescript-eslint/parser": [
|
||||||
|
".ts",
|
||||||
|
".tsx",
|
||||||
|
".cts",
|
||||||
|
".mts"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"import-x/resolver": {
|
||||||
|
"node": {
|
||||||
|
"extensions": [
|
||||||
|
".js",
|
||||||
|
".web.js",
|
||||||
|
".ios.js",
|
||||||
|
".android.js"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ignorePatterns": [
|
||||||
|
"**/__mocks__/*.ts",
|
||||||
|
"ios/**",
|
||||||
|
"android/**",
|
||||||
|
"coverage/**",
|
||||||
|
"*.lock",
|
||||||
|
".husky/**",
|
||||||
|
"patches/**",
|
||||||
|
"*.html",
|
||||||
|
"bskyweb/**",
|
||||||
|
"bskyembed/**",
|
||||||
|
"bskyogcard/**",
|
||||||
|
"src/locale/locales/_build/**",
|
||||||
|
"src/locale/locales/**/*.js",
|
||||||
|
"*.e2e.ts",
|
||||||
|
"*.e2e.tsx",
|
||||||
|
"eslint.config.mjs",
|
||||||
|
".jscodeshift/**"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"constructor-super": "error",
|
||||||
|
"for-direction": "error",
|
||||||
|
"getter-return": "error",
|
||||||
|
"no-async-promise-executor": "error",
|
||||||
|
"no-case-declarations": "error",
|
||||||
|
"no-class-assign": "error",
|
||||||
|
"no-compare-neg-zero": "error",
|
||||||
|
"no-cond-assign": "error",
|
||||||
|
"no-const-assign": "error",
|
||||||
|
"no-constant-binary-expression": "error",
|
||||||
|
"no-constant-condition": "error",
|
||||||
|
"no-control-regex": "error",
|
||||||
|
"no-debugger": "error",
|
||||||
|
"no-delete-var": "error",
|
||||||
|
"no-dupe-class-members": "error",
|
||||||
|
"no-dupe-else-if": "error",
|
||||||
|
"no-dupe-keys": "error",
|
||||||
|
"no-duplicate-case": "error",
|
||||||
|
"no-empty": "error",
|
||||||
|
"no-empty-character-class": "error",
|
||||||
|
"no-empty-pattern": "error",
|
||||||
|
"no-empty-static-block": "error",
|
||||||
|
"no-ex-assign": "error",
|
||||||
|
"no-extra-boolean-cast": "error",
|
||||||
|
"no-fallthrough": "error",
|
||||||
|
"no-func-assign": "error",
|
||||||
|
"no-global-assign": "error",
|
||||||
|
"no-import-assign": "error",
|
||||||
|
"no-invalid-regexp": "error",
|
||||||
|
"no-irregular-whitespace": "error",
|
||||||
|
"no-loss-of-precision": "error",
|
||||||
|
"no-misleading-character-class": "error",
|
||||||
|
"no-new-native-nonconstructor": "error",
|
||||||
|
"no-nonoctal-decimal-escape": "error",
|
||||||
|
"no-obj-calls": "error",
|
||||||
|
"no-prototype-builtins": "error",
|
||||||
|
"no-redeclare": "error",
|
||||||
|
"no-regex-spaces": "error",
|
||||||
|
"no-self-assign": "error",
|
||||||
|
"no-setter-return": "error",
|
||||||
|
"no-shadow-restricted-names": "error",
|
||||||
|
"no-sparse-arrays": "error",
|
||||||
|
"no-this-before-super": "error",
|
||||||
|
"no-unexpected-multiline": "error",
|
||||||
|
"no-unreachable": "error",
|
||||||
|
"no-unsafe-finally": "error",
|
||||||
|
"no-unsafe-negation": "error",
|
||||||
|
"no-unsafe-optional-chaining": "error",
|
||||||
|
"no-unused-labels": "error",
|
||||||
|
"no-unused-private-class-members": "error",
|
||||||
|
"no-unused-vars": "error",
|
||||||
|
"no-useless-backreference": "error",
|
||||||
|
"no-useless-catch": "error",
|
||||||
|
"no-useless-escape": "error",
|
||||||
|
"no-with": "error",
|
||||||
|
"require-yield": "error",
|
||||||
|
"use-isnan": "error",
|
||||||
|
"valid-typeof": "error",
|
||||||
|
"no-array-constructor": "error",
|
||||||
|
"no-unused-expressions": "error",
|
||||||
|
"import/namespace": "off",
|
||||||
|
"import/default": "error",
|
||||||
|
"import/no-named-as-default": "warn",
|
||||||
|
"import/no-named-as-default-member": "warn",
|
||||||
|
"import/no-duplicates": "warn",
|
||||||
|
"react/rules-of-hooks": "error",
|
||||||
|
"react/exhaustive-deps": "warn",
|
||||||
|
"typescript/await-thenable": "error",
|
||||||
|
"typescript/ban-ts-comment": "error",
|
||||||
|
"typescript/no-array-delete": "error",
|
||||||
|
"typescript/no-base-to-string": "error",
|
||||||
|
"typescript/no-duplicate-enum-values": "error",
|
||||||
|
"typescript/no-duplicate-type-constituents": "error",
|
||||||
|
"typescript/no-empty-object-type": "error",
|
||||||
|
"typescript/no-explicit-any": "error",
|
||||||
|
"typescript/no-extra-non-null-assertion": "error",
|
||||||
|
"typescript/no-floating-promises": "error",
|
||||||
|
"typescript/no-for-in-array": "error",
|
||||||
|
"typescript/no-implied-eval": "error",
|
||||||
|
"typescript/no-misused-new": "error",
|
||||||
|
"typescript/no-misused-promises": "error",
|
||||||
|
"typescript/no-namespace": "error",
|
||||||
|
"typescript/no-non-null-asserted-optional-chain": "error",
|
||||||
|
"typescript/no-redundant-type-constituents": "error",
|
||||||
|
"typescript/no-require-imports": "error",
|
||||||
|
"typescript/no-this-alias": "error",
|
||||||
|
"typescript/no-unnecessary-type-assertion": "error",
|
||||||
|
"typescript/no-unnecessary-type-constraint": "error",
|
||||||
|
"typescript/no-unsafe-argument": "error",
|
||||||
|
"typescript/no-unsafe-assignment": "error",
|
||||||
|
"typescript/no-unsafe-call": "error",
|
||||||
|
"typescript/no-unsafe-declaration-merging": "error",
|
||||||
|
"typescript/no-unsafe-enum-comparison": "error",
|
||||||
|
"typescript/no-unsafe-function-type": "error",
|
||||||
|
"typescript/no-unsafe-member-access": "error",
|
||||||
|
"typescript/no-unsafe-return": "error",
|
||||||
|
"typescript/no-unsafe-unary-minus": "error",
|
||||||
|
"typescript/no-wrapper-object-types": "error",
|
||||||
|
"typescript/only-throw-error": "error",
|
||||||
|
"typescript/prefer-as-const": "error",
|
||||||
|
"typescript/prefer-namespace-keyword": "error",
|
||||||
|
"typescript/prefer-promise-reject-errors": "error",
|
||||||
|
"typescript/require-await": "error",
|
||||||
|
"typescript/restrict-plus-operands": "error",
|
||||||
|
"typescript/restrict-template-expressions": "error",
|
||||||
|
"typescript/triple-slash-reference": "error",
|
||||||
|
"typescript/unbound-method": "error"
|
||||||
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
"**/*.mts",
|
||||||
|
"**/*.cts"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"constructor-super": "off",
|
||||||
|
"getter-return": "off",
|
||||||
|
"no-class-assign": "off",
|
||||||
|
"no-const-assign": "off",
|
||||||
|
"no-dupe-class-members": "off",
|
||||||
|
"no-dupe-keys": "off",
|
||||||
|
"no-func-assign": "off",
|
||||||
|
"no-import-assign": "off",
|
||||||
|
"no-new-native-nonconstructor": "off",
|
||||||
|
"no-obj-calls": "off",
|
||||||
|
"no-redeclare": "off",
|
||||||
|
"no-setter-return": "off",
|
||||||
|
"no-this-before-super": "off",
|
||||||
|
"no-unreachable": "off",
|
||||||
|
"no-unsafe-negation": "off",
|
||||||
|
"no-var": "error",
|
||||||
|
"no-with": "off",
|
||||||
|
"prefer-const": "error",
|
||||||
|
"prefer-rest-params": "error",
|
||||||
|
"prefer-spread": "error"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"**/*.{js,jsx,ts,tsx}"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"bsky-internal/avoid-unwrapped-text": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"impliedTextComponents": [
|
||||||
|
"H1",
|
||||||
|
"H2",
|
||||||
|
"H3",
|
||||||
|
"H4",
|
||||||
|
"H5",
|
||||||
|
"H6",
|
||||||
|
"P",
|
||||||
|
"Admonition",
|
||||||
|
"Admonition.Admonition",
|
||||||
|
"Toast.Action",
|
||||||
|
"AgeAssuranceAdmonition",
|
||||||
|
"Span",
|
||||||
|
"StackedButton"
|
||||||
|
],
|
||||||
|
"impliedTextProps": [],
|
||||||
|
"suggestedTextWrappers": {
|
||||||
|
"Button": "ButtonText",
|
||||||
|
"ToggleButton.Button": "ToggleButton.ButtonText",
|
||||||
|
"SegmentedControl.Item": "SegmentedControl.ItemText"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"bsky-internal/use-exact-imports": "error",
|
||||||
|
"bsky-internal/use-prefixed-imports": "error",
|
||||||
|
"bsky-internal/lingui-msg-rule": "error",
|
||||||
|
"react/display-name": "error",
|
||||||
|
"react/jsx-key": "error",
|
||||||
|
"react/jsx-no-comment-textnodes": "error",
|
||||||
|
"react/jsx-no-duplicate-props": "error",
|
||||||
|
"react/jsx-no-target-blank": "error",
|
||||||
|
"react/jsx-no-undef": "error",
|
||||||
|
"react/no-children-prop": "error",
|
||||||
|
"react/no-danger-with-children": "error",
|
||||||
|
"react/no-direct-mutation-state": "error",
|
||||||
|
"react/no-find-dom-node": "error",
|
||||||
|
"react/no-is-mounted": "error",
|
||||||
|
"react/no-render-return-value": "error",
|
||||||
|
"react/no-string-refs": "error",
|
||||||
|
"react/no-unescaped-entities": "off",
|
||||||
|
"react/no-unknown-property": "error",
|
||||||
|
"react/no-unsafe": "off",
|
||||||
|
"react/react-in-jsx-scope": "off",
|
||||||
|
"react/hook-use-state": "warn",
|
||||||
|
"react-native/no-inline-styles": "off",
|
||||||
|
"react-native-a11y/has-accessibility-hint": "error",
|
||||||
|
"react-native-a11y/has-accessibility-props": "error",
|
||||||
|
"react-native-a11y/has-valid-accessibility-actions": "error",
|
||||||
|
"react-native-a11y/has-valid-accessibility-component-type": "error",
|
||||||
|
"react-native-a11y/has-valid-accessibility-descriptors": "error",
|
||||||
|
"react-native-a11y/has-valid-accessibility-role": "error",
|
||||||
|
"react-native-a11y/has-valid-accessibility-state": "error",
|
||||||
|
"react-native-a11y/has-valid-accessibility-states": "error",
|
||||||
|
"react-native-a11y/has-valid-accessibility-traits": "error",
|
||||||
|
"react-native-a11y/has-valid-accessibility-value": "error",
|
||||||
|
"react-native-a11y/no-nested-touchables": "error",
|
||||||
|
"react-native-a11y/has-valid-accessibility-ignores-invert-colors": "error",
|
||||||
|
"react-native-a11y/has-valid-accessibility-live-region": "error",
|
||||||
|
"react-native-a11y/has-valid-important-for-accessibility": "error",
|
||||||
|
"react-compiler/react-compiler": "warn",
|
||||||
|
"simple-import-sort/imports": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"groups": [
|
||||||
|
[
|
||||||
|
"^\\u0000"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"^node:"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"^(react\\/(.*)$)|^(react$)|^(react-native(.*)$)",
|
||||||
|
"^(expo(.*)$)|^(expo$)",
|
||||||
|
"^(?!(?:alf|components|lib|locale|logger|platform|screens|state|view)(?:$|\\/))@?\\w"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"^(?:#\\/)?(?:lib|state|logger|platform|locale)(?:$|\\/)",
|
||||||
|
"^(?:#\\/)?view(?:$|\\/)",
|
||||||
|
"^(?:#\\/)?screens(?:$|\\/)",
|
||||||
|
"^(?:#\\/)?alf(?:$|\\/)",
|
||||||
|
"^(?:#\\/)?components(?:$|\\/)",
|
||||||
|
"^#\\/",
|
||||||
|
"^\\."
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"^"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"simple-import-sort/exports": "error",
|
||||||
|
"no-unused-vars": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"argsIgnorePattern": "^_",
|
||||||
|
"varsIgnorePattern": "^_.+",
|
||||||
|
"caughtErrors": "none",
|
||||||
|
"ignoreRestSiblings": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"no-restricted-imports": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"paths": [
|
||||||
|
{
|
||||||
|
"name": "react",
|
||||||
|
"importNames": [
|
||||||
|
"React",
|
||||||
|
"default"
|
||||||
|
],
|
||||||
|
"message": "React is already in the global type namespace. Use named imports for runtime modules."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"no-empty-pattern": "off",
|
||||||
|
"no-async-promise-executor": "off",
|
||||||
|
"no-constant-binary-expression": "warn",
|
||||||
|
"prefer-const": "off",
|
||||||
|
"no-empty": "off",
|
||||||
|
"no-unsafe-optional-chaining": "off",
|
||||||
|
"no-prototype-builtins": "off",
|
||||||
|
"no-var": "off",
|
||||||
|
"prefer-rest-params": "off",
|
||||||
|
"no-case-declarations": "off",
|
||||||
|
"no-irregular-whitespace": "off",
|
||||||
|
"no-useless-escape": "off",
|
||||||
|
"no-sparse-arrays": "off",
|
||||||
|
"no-fallthrough": "off",
|
||||||
|
"no-control-regex": "off",
|
||||||
|
"no-unused-expressions": [
|
||||||
|
"error",
|
||||||
|
{
|
||||||
|
"allowTernary": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"import/consistent-type-specifier-style": [
|
||||||
|
"warn",
|
||||||
|
"prefer-inline"
|
||||||
|
],
|
||||||
|
"import/no-nodejs-modules": "error",
|
||||||
|
"typescript/consistent-type-imports": [
|
||||||
|
"warn",
|
||||||
|
{
|
||||||
|
"prefer": "type-imports",
|
||||||
|
"fixStyle": "inline-type-imports"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"typescript/no-require-imports": "off",
|
||||||
|
"typescript/ban-ts-comment": "off",
|
||||||
|
"typescript/no-empty-object-type": "off",
|
||||||
|
"typescript/no-unsafe-function-type": "off",
|
||||||
|
"typescript/no-unsafe-assignment": "off",
|
||||||
|
"typescript/unbound-method": "off",
|
||||||
|
"typescript/no-unsafe-argument": "off",
|
||||||
|
"typescript/no-unsafe-return": "off"
|
||||||
|
},
|
||||||
|
"jsPlugins": [
|
||||||
|
"eslint-plugin-bsky-internal",
|
||||||
|
"eslint-plugin-react-native",
|
||||||
|
"eslint-plugin-react-native-a11y",
|
||||||
|
"eslint-plugin-react-compiler",
|
||||||
|
"eslint-plugin-simple-import-sort"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"es2026": true,
|
||||||
|
"browser": true,
|
||||||
|
"node": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"bskyogcard/**/*.{js,jsx,ts,tsx}",
|
||||||
|
"dev-env/**/*.{js,jsx,ts,tsx}"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
"import/no-nodejs-modules": "off"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"files": [
|
||||||
|
"**/__tests__/**/*.{js,jsx,ts,tsx}",
|
||||||
|
"**/*.test.{js,jsx,ts,tsx}"
|
||||||
|
],
|
||||||
|
"env": {
|
||||||
|
"jest": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -30,7 +30,7 @@ pnpm ios # Run on iOS
|
|||||||
# Testing & Quality
|
# Testing & Quality
|
||||||
# IMPORTANT: Always use these pnpm scripts, never call the underlying tools directly
|
# IMPORTANT: Always use these pnpm scripts, never call the underlying tools directly
|
||||||
pnpm test # Run Jest tests
|
pnpm test # Run Jest tests
|
||||||
pnpm lint # Run ESLint
|
pnpm lint # Run Oxlint
|
||||||
pnpm typecheck # Run TypeScript type checking
|
pnpm typecheck # Run TypeScript type checking
|
||||||
pnpm prettier # Run Prettier for code formatting
|
pnpm prettier # Run Prettier for code formatting
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,319 +0,0 @@
|
|||||||
// @ts-check
|
|
||||||
import js from '@eslint/js'
|
|
||||||
import tseslint from 'typescript-eslint'
|
|
||||||
import {defineConfig} from 'eslint/config'
|
|
||||||
import react from 'eslint-plugin-react'
|
|
||||||
import reactHooks from 'eslint-plugin-react-hooks'
|
|
||||||
// @ts-expect-error no types
|
|
||||||
import reactNative from 'eslint-plugin-react-native'
|
|
||||||
// @ts-expect-error no types
|
|
||||||
import reactNativeA11y from 'eslint-plugin-react-native-a11y'
|
|
||||||
import simpleImportSort from 'eslint-plugin-simple-import-sort'
|
|
||||||
import importX from 'eslint-plugin-import-x'
|
|
||||||
import lingui from 'eslint-plugin-lingui'
|
|
||||||
import reactCompiler from 'eslint-plugin-react-compiler'
|
|
||||||
import bskyInternal from 'eslint-plugin-bsky-internal'
|
|
||||||
import globals from 'globals'
|
|
||||||
import tsParser from '@typescript-eslint/parser'
|
|
||||||
|
|
||||||
export default defineConfig(
|
|
||||||
/**
|
|
||||||
* Global ignores
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
ignores: [
|
|
||||||
'**/__mocks__/*.ts',
|
|
||||||
'ios/**',
|
|
||||||
'android/**',
|
|
||||||
'coverage/**',
|
|
||||||
'*.lock',
|
|
||||||
'.husky/**',
|
|
||||||
'patches/**',
|
|
||||||
'*.html',
|
|
||||||
'bskyweb/**',
|
|
||||||
'bskyembed/**',
|
|
||||||
'bskyogcard/**',
|
|
||||||
'src/locale/locales/_build/**',
|
|
||||||
'src/locale/locales/**/*.js',
|
|
||||||
'*.e2e.ts',
|
|
||||||
'*.e2e.tsx',
|
|
||||||
'eslint.config.mjs',
|
|
||||||
'babel.config.js',
|
|
||||||
'metro.config.js',
|
|
||||||
'.jscodeshift/**',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base configurations
|
|
||||||
*/
|
|
||||||
js.configs.recommended,
|
|
||||||
tseslint.configs.recommendedTypeChecked,
|
|
||||||
reactHooks.configs.flat.recommended,
|
|
||||||
importX.flatConfigs.recommended,
|
|
||||||
importX.flatConfigs.typescript,
|
|
||||||
importX.flatConfigs['react-native'],
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Main configuration for all JS/TS/JSX/TSX files
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
files: ['**/*.{js,jsx,ts,tsx}'],
|
|
||||||
plugins: {
|
|
||||||
react,
|
|
||||||
'react-native': reactNative,
|
|
||||||
'react-native-a11y': reactNativeA11y,
|
|
||||||
'simple-import-sort': simpleImportSort,
|
|
||||||
// @ts-expect-error - not sure why
|
|
||||||
lingui,
|
|
||||||
'react-compiler': reactCompiler,
|
|
||||||
'bsky-internal': bskyInternal,
|
|
||||||
},
|
|
||||||
languageOptions: {
|
|
||||||
ecmaVersion: 'latest',
|
|
||||||
sourceType: 'module',
|
|
||||||
globals: {
|
|
||||||
...globals.browser,
|
|
||||||
...globals.node,
|
|
||||||
},
|
|
||||||
parserOptions: {
|
|
||||||
parser: tsParser,
|
|
||||||
projectService: true,
|
|
||||||
tsconfigRootDir: import.meta.dirname,
|
|
||||||
ecmaFeatures: {
|
|
||||||
jsx: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
settings: {
|
|
||||||
react: {
|
|
||||||
version: 'detect',
|
|
||||||
},
|
|
||||||
componentWrapperFunctions: ['observer'],
|
|
||||||
},
|
|
||||||
rules: {
|
|
||||||
/**
|
|
||||||
* Custom rules
|
|
||||||
*/
|
|
||||||
'bsky-internal/avoid-unwrapped-text': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
impliedTextComponents: [
|
|
||||||
'H1',
|
|
||||||
'H2',
|
|
||||||
'H3',
|
|
||||||
'H4',
|
|
||||||
'H5',
|
|
||||||
'H6',
|
|
||||||
'P',
|
|
||||||
'Admonition',
|
|
||||||
'Admonition.Admonition',
|
|
||||||
'Toast.Action',
|
|
||||||
'AgeAssuranceAdmonition',
|
|
||||||
'Span',
|
|
||||||
'StackedButton',
|
|
||||||
],
|
|
||||||
impliedTextProps: [],
|
|
||||||
suggestedTextWrappers: {
|
|
||||||
Button: 'ButtonText',
|
|
||||||
'ToggleButton.Button': 'ToggleButton.ButtonText',
|
|
||||||
'SegmentedControl.Item': 'SegmentedControl.ItemText',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'bsky-internal/use-exact-imports': 'error',
|
|
||||||
'bsky-internal/use-prefixed-imports': 'error',
|
|
||||||
'bsky-internal/lingui-msg-rule': 'error',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* React & React Native
|
|
||||||
*/
|
|
||||||
...react.configs.recommended.rules,
|
|
||||||
...react.configs['jsx-runtime'].rules,
|
|
||||||
'react/hook-use-state': 'warn',
|
|
||||||
'react/no-unescaped-entities': 'off',
|
|
||||||
'react/prop-types': 'off',
|
|
||||||
'react-native/no-inline-styles': 'off',
|
|
||||||
...reactNativeA11y.configs.all.rules,
|
|
||||||
'react-compiler/react-compiler': 'warn',
|
|
||||||
'react-hooks/set-state-in-effect': 'error',
|
|
||||||
'react-hooks/purity': 'error',
|
|
||||||
'react-hooks/refs': 'error',
|
|
||||||
'react-hooks/immutability': 'error',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Import sorting
|
|
||||||
*/
|
|
||||||
'simple-import-sort/imports': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
groups: [
|
|
||||||
// Side effect imports.
|
|
||||||
['^\\u0000'],
|
|
||||||
// Node.js builtins prefixed with `node:`.
|
|
||||||
['^node:'],
|
|
||||||
// Packages.
|
|
||||||
// Things that start with a letter (or digit or underscore), or `@` followed by a letter.
|
|
||||||
// React/React Native prioritized, followed by expo
|
|
||||||
// Followed by all packages excluding unprefixed relative ones
|
|
||||||
[
|
|
||||||
'^(react\\/(.*)$)|^(react$)|^(react-native(.*)$)',
|
|
||||||
'^(expo(.*)$)|^(expo$)',
|
|
||||||
'^(?!(?:alf|components|lib|locale|logger|platform|screens|state|view)(?:$|\\/))@?\\w',
|
|
||||||
],
|
|
||||||
// Relative imports.
|
|
||||||
// Ideally, anything that starts with a dot or #
|
|
||||||
// due to unprefixed relative imports being used, we whitelist the relative paths we use
|
|
||||||
// (?:$|\\/) matches end of string or /
|
|
||||||
[
|
|
||||||
'^(?:#\\/)?(?:lib|state|logger|platform|locale)(?:$|\\/)',
|
|
||||||
'^(?:#\\/)?view(?:$|\\/)',
|
|
||||||
'^(?:#\\/)?screens(?:$|\\/)',
|
|
||||||
'^(?:#\\/)?alf(?:$|\\/)',
|
|
||||||
'^(?:#\\/)?components(?:$|\\/)',
|
|
||||||
'^#\\/',
|
|
||||||
'^\\.',
|
|
||||||
],
|
|
||||||
// anything else - hopefully we don't have any of these
|
|
||||||
['^'],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'simple-import-sort/exports': 'error',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Import linting
|
|
||||||
*/
|
|
||||||
'import-x/consistent-type-specifier-style': ['warn', 'prefer-inline'],
|
|
||||||
'import-x/no-unresolved': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* The `postinstall` hook runs `compile-if-needed` locally, but not in
|
|
||||||
* CI. For CI-sake, ignore this.
|
|
||||||
*/
|
|
||||||
ignore: ['^#\/locale\/locales\/.+\/messages'],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'import-x/no-extraneous-dependencies': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
whitelist: [
|
|
||||||
// test files only
|
|
||||||
'@jest/globals',
|
|
||||||
// we only use a really simple util from this, and we know it will be present
|
|
||||||
'expo-modules-core',
|
|
||||||
// this is a dep for @atproto/api, but we absolutely need them in sync, so just
|
|
||||||
// rely on the transient version
|
|
||||||
'@atproto/common-web',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'import-x/no-nodejs-modules': 'error',
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TypeScript-specific rules
|
|
||||||
*/
|
|
||||||
'no-unused-vars': 'off', // off, we use TS-specific rule below
|
|
||||||
'@typescript-eslint/no-unused-vars': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
argsIgnorePattern: '^_',
|
|
||||||
varsIgnorePattern: '^_.+',
|
|
||||||
caughtErrors: 'none',
|
|
||||||
ignoreRestSiblings: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
'@typescript-eslint/consistent-type-imports': [
|
|
||||||
'warn',
|
|
||||||
{prefer: 'type-imports', fixStyle: 'inline-type-imports'},
|
|
||||||
],
|
|
||||||
'@typescript-eslint/no-require-imports': 'off',
|
|
||||||
'@typescript-eslint/no-unused-expressions': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
allowTernary: true,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
/**
|
|
||||||
* Maintain previous behavior via eslint-suppressions.json - these are
|
|
||||||
* stricter in typescript-eslint v8. `off` ones are a bit too nit-picky.
|
|
||||||
*/
|
|
||||||
'@typescript-eslint/no-explicit-any': 'error',
|
|
||||||
'@typescript-eslint/ban-ts-comment': 'off',
|
|
||||||
'@typescript-eslint/no-empty-object-type': 'off',
|
|
||||||
'@typescript-eslint/no-unsafe-function-type': 'off',
|
|
||||||
'@typescript-eslint/no-unsafe-assignment': 'off',
|
|
||||||
'@typescript-eslint/unbound-method': 'off',
|
|
||||||
'@typescript-eslint/no-unsafe-argument': 'off',
|
|
||||||
'@typescript-eslint/no-unsafe-return': 'off',
|
|
||||||
'@typescript-eslint/no-unsafe-member-access': 'error',
|
|
||||||
'@typescript-eslint/no-unsafe-call': 'error',
|
|
||||||
'@typescript-eslint/no-floating-promises': 'error',
|
|
||||||
'@typescript-eslint/no-misused-promises': 'error',
|
|
||||||
'@typescript-eslint/require-await': 'error',
|
|
||||||
'@typescript-eslint/no-unsafe-enum-comparison': 'error',
|
|
||||||
'@typescript-eslint/no-unnecessary-type-assertion': 'error',
|
|
||||||
'@typescript-eslint/no-redundant-type-constituents': 'error',
|
|
||||||
'@typescript-eslint/no-duplicate-type-constituents': 'error',
|
|
||||||
'@typescript-eslint/no-base-to-string': 'error',
|
|
||||||
'@typescript-eslint/prefer-promise-reject-errors': 'error',
|
|
||||||
'@typescript-eslint/await-thenable': 'error',
|
|
||||||
|
|
||||||
'no-restricted-imports': [
|
|
||||||
'error',
|
|
||||||
{
|
|
||||||
paths: [
|
|
||||||
{
|
|
||||||
name: 'react',
|
|
||||||
importNames: ['React', 'default'],
|
|
||||||
message:
|
|
||||||
'React is already in the global type namespace. Use named imports for runtime modules.',
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Turn off rules that we haven't enforced thus far
|
|
||||||
*/
|
|
||||||
'no-empty-pattern': 'off',
|
|
||||||
'no-async-promise-executor': 'off',
|
|
||||||
'no-constant-binary-expression': 'warn',
|
|
||||||
'prefer-const': 'off',
|
|
||||||
'no-empty': 'off',
|
|
||||||
'no-unsafe-optional-chaining': 'off',
|
|
||||||
'no-prototype-builtins': 'off',
|
|
||||||
'no-var': 'off',
|
|
||||||
'prefer-rest-params': 'off',
|
|
||||||
'no-case-declarations': 'off',
|
|
||||||
'no-irregular-whitespace': 'off',
|
|
||||||
'no-useless-escape': 'off',
|
|
||||||
'no-sparse-arrays': 'off',
|
|
||||||
'no-fallthrough': 'off',
|
|
||||||
'no-control-regex': 'off',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bskyogcard, dev-env - server-side, Node.js imports are fine
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
files: ['bskyogcard/**/*.{js,jsx,ts,tsx}', 'dev-env/**/*.{js,jsx,ts,tsx}'],
|
|
||||||
rules: {
|
|
||||||
'import-x/no-nodejs-modules': 'off',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Test files configuration
|
|
||||||
*/
|
|
||||||
{
|
|
||||||
files: ['**/__tests__/**/*.{js,jsx,ts,tsx}', '**/*.test.{js,jsx,ts,tsx}'],
|
|
||||||
languageOptions: {
|
|
||||||
globals: {
|
|
||||||
...globals.jest,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
)
|
|
||||||
+3
-8
@@ -1,16 +1,11 @@
|
|||||||
const {RuleTester} = require('eslint')
|
const {RuleTester} = require('oxlint/plugins-dev')
|
||||||
const tseslint = require('typescript-eslint')
|
|
||||||
const avoidUnwrappedText = require('../avoid-unwrapped-text')
|
const avoidUnwrappedText = require('../avoid-unwrapped-text')
|
||||||
|
|
||||||
const ruleTester = new RuleTester({
|
const ruleTester = new RuleTester({
|
||||||
|
eslintCompat: true,
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
parser: tseslint.parser,
|
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaFeatures: {
|
lang: 'tsx',
|
||||||
jsx: true,
|
|
||||||
},
|
|
||||||
ecmaVersion: 'latest',
|
|
||||||
sourceType: 'module',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
+3
-8
@@ -1,16 +1,11 @@
|
|||||||
const {RuleTester} = require('eslint')
|
const {RuleTester} = require('oxlint/plugins-dev')
|
||||||
const tseslint = require('typescript-eslint')
|
|
||||||
const linguiMsgRule = require('../lingui-msg-rule')
|
const linguiMsgRule = require('../lingui-msg-rule')
|
||||||
|
|
||||||
const ruleTester = new RuleTester({
|
const ruleTester = new RuleTester({
|
||||||
|
eslintCompat: true,
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
parser: tseslint.parser,
|
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaFeatures: {
|
lang: 'tsx',
|
||||||
jsx: true,
|
|
||||||
},
|
|
||||||
ecmaVersion: 'latest',
|
|
||||||
sourceType: 'module',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
## Eslint plugin tests
|
||||||
|
|
||||||
|
These are disabled as Oxlint’s RuleTester doesn’t work well with Hermes.
|
||||||
File diff suppressed because it is too large
Load Diff
+4
-10
@@ -59,7 +59,7 @@
|
|||||||
"test-watch": "NODE_ENV=test jest --watchAll",
|
"test-watch": "NODE_ENV=test jest --watchAll",
|
||||||
"test-ci": "NODE_ENV=test jest --ci --forceExit --reporters=default --reporters=jest-junit",
|
"test-ci": "NODE_ENV=test jest --ci --forceExit --reporters=default --reporters=jest-junit",
|
||||||
"test-coverage": "NODE_ENV=test jest --coverage",
|
"test-coverage": "NODE_ENV=test jest --coverage",
|
||||||
"lint": "eslint --cache --quiet src modules",
|
"lint": "oxlint --quiet src modules",
|
||||||
"lint-native": "swiftlint ./modules && ktlint ./modules",
|
"lint-native": "swiftlint ./modules && ktlint ./modules",
|
||||||
"lint-native:fix": "swiftlint --fix ./modules && ktlint --format ./modules",
|
"lint-native:fix": "swiftlint --fix ./modules && ktlint --format ./modules",
|
||||||
"typecheck": "tsgo --project ./tsconfig.check.json",
|
"typecheck": "tsgo --project ./tsconfig.check.json",
|
||||||
@@ -256,7 +256,6 @@
|
|||||||
"@babel/preset-env": "^7.26.0",
|
"@babel/preset-env": "^7.26.0",
|
||||||
"@babel/runtime": "^7.26.0",
|
"@babel/runtime": "^7.26.0",
|
||||||
"@crowdin/cli": "^4.14.1",
|
"@crowdin/cli": "^4.14.1",
|
||||||
"@eslint/js": "^9.39.2",
|
|
||||||
"@lingui/babel-plugin-lingui-macro": "^5.9.2",
|
"@lingui/babel-plugin-lingui-macro": "^5.9.2",
|
||||||
"@lingui/cli": "^5.9.2",
|
"@lingui/cli": "^5.9.2",
|
||||||
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.15",
|
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.15",
|
||||||
@@ -276,14 +275,8 @@
|
|||||||
"babel-plugin-module-resolver": "^5.0.2",
|
"babel-plugin-module-resolver": "^5.0.2",
|
||||||
"babel-plugin-react-compiler": "19.1.0-rc.3",
|
"babel-plugin-react-compiler": "19.1.0-rc.3",
|
||||||
"babel-preset-expo": "~54.0.10",
|
"babel-preset-expo": "~54.0.10",
|
||||||
"eslint": "^9.39.2",
|
|
||||||
"eslint-import-resolver-typescript": "^4.4.4",
|
|
||||||
"eslint-plugin-bsky-internal": "link:eslint",
|
"eslint-plugin-bsky-internal": "link:eslint",
|
||||||
"eslint-plugin-import-x": "^4.16.2",
|
|
||||||
"eslint-plugin-lingui": "^0.12.0",
|
|
||||||
"eslint-plugin-react": "^7.37.5",
|
|
||||||
"eslint-plugin-react-compiler": "19.1.0-rc.2",
|
"eslint-plugin-react-compiler": "19.1.0-rc.2",
|
||||||
"eslint-plugin-react-hooks": "^7.1.1",
|
|
||||||
"eslint-plugin-react-native": "^5.0.0",
|
"eslint-plugin-react-native": "^5.0.0",
|
||||||
"eslint-plugin-react-native-a11y": "^3.5.1",
|
"eslint-plugin-react-native-a11y": "^3.5.1",
|
||||||
"eslint-plugin-simple-import-sort": "^13.0.0",
|
"eslint-plugin-simple-import-sort": "^13.0.0",
|
||||||
@@ -295,13 +288,14 @@
|
|||||||
"jest-expo": "~54.0.17",
|
"jest-expo": "~54.0.17",
|
||||||
"jest-junit": "^16.0.0",
|
"jest-junit": "^16.0.0",
|
||||||
"lint-staged": "^17.0.8",
|
"lint-staged": "^17.0.8",
|
||||||
|
"oxlint": "^1.73.0",
|
||||||
|
"oxlint-tsgolint": "^0.24.0",
|
||||||
"prettier": "^3.8.3",
|
"prettier": "^3.8.3",
|
||||||
"react-native-dotenv": "^3.4.11",
|
"react-native-dotenv": "^3.4.11",
|
||||||
"react-refresh": "^0.14.0",
|
"react-refresh": "^0.14.0",
|
||||||
"svgo": "^3.3.2",
|
"svgo": "^3.3.2",
|
||||||
"ts-plugin-sort-import-suggestions": "^1.0.4",
|
"ts-plugin-sort-import-suggestions": "^1.0.4",
|
||||||
"typescript": "^6.0.2",
|
"typescript": "^6.0.2",
|
||||||
"typescript-eslint": "^8.58.0",
|
|
||||||
"webpack-bundle-analyzer": "^4.10.1"
|
"webpack-bundle-analyzer": "^4.10.1"
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
@@ -366,7 +360,7 @@
|
|||||||
},
|
},
|
||||||
"lint-staged": {
|
"lint-staged": {
|
||||||
"*{.js,.jsx,.ts,.tsx}": [
|
"*{.js,.jsx,.ts,.tsx}": [
|
||||||
"eslint --cache --fix"
|
"oxlint --fix"
|
||||||
],
|
],
|
||||||
"*{.js,.jsx,.ts,.tsx,.css}": [
|
"*{.js,.jsx,.ts,.tsx,.css}": [
|
||||||
"prettier --cache --write --ignore-unknown"
|
"prettier --cache --write --ignore-unknown"
|
||||||
|
|||||||
Generated
+292
-1108
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user