Skip to content

Commit 5e875f4

Browse files
antonisclaude
andcommitted
chore(core): Migrate from ESLint to oxlint
Replace ESLint with oxlint for ~430x faster linting (30s → 70ms). Follows the same pattern as sentry-javascript#19134. Changes: - Add .oxlintrc.json with rule parity to the previous ESLint config - Use jsPlugins for @sentry-internal/eslint-plugin-sdk custom rules - Migrate all eslint-disable comments to oxlint-disable format - Remove unused disable directives (rules already off in config) - Remove ESLint dependencies and config files - Clean up ESLint-related yarn resolutions Known gaps (same as sentry-javascript): - No import sorting (simple-import-sort has no oxlint equivalent) - No naming-convention, member-ordering, explicit-member-accessibility - sdk/no-regexp-constructor disabled (inline disable not supported for jsPlugin rules) Closes #5615 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent d7c03d0 commit 5e875f4

74 files changed

Lines changed: 427 additions & 553 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

package.json

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -66,23 +66,9 @@
6666
"front-matter@npm:4.0.2/js-yaml": "^3.14.2",
6767
"js-yaml": "^4.1.1",
6868
"detox@npm:20.46.0/ajv": "^8.18.0",
69-
"@eslint/eslintrc@npm:2.1.4/ajv": "^6.14.0",
70-
"@eslint/eslintrc@npm:3.3.3/ajv": "^6.14.0",
71-
"eslint@npm:9.39.4/ajv": "^6.14.0",
7269
"express@npm:4.19.2/path-to-regexp": "0.1.12",
73-
"@eslint/config-array@npm:0.21.1/minimatch": "^3.1.3",
74-
"@eslint/eslintrc@npm:2.1.4/minimatch": "^3.1.3",
75-
"@eslint/eslintrc@npm:3.3.3/minimatch": "^3.1.3",
7670
"@expo/fingerprint@npm:0.6.1/minimatch": "^3.1.3",
77-
"@humanwhocodes/config-array@npm:0.11.14/minimatch": "^3.1.3",
78-
"@humanwhocodes/config-array@npm:0.13.0/minimatch": "^3.1.3",
7971
"@lerna/create@npm:8.1.8/minimatch": "^3.1.3",
80-
"eslint-plugin-import@npm:2.31.0/minimatch": "^3.1.3",
81-
"eslint-plugin-import@npm:2.32.0/minimatch": "^3.1.3",
82-
"eslint-plugin-node@npm:11.1.0/minimatch": "^3.1.3",
83-
"eslint-plugin-react@npm:7.35.0/minimatch": "^3.1.3",
84-
"eslint-plugin-react@npm:7.37.5/minimatch": "^3.1.3",
85-
"eslint@npm:9.39.4/minimatch": "^3.1.3",
8672
"glob@npm:6.0.4/minimatch": "^3.1.3",
8773
"glob@npm:7.1.6/minimatch": "^3.1.3",
8874
"glob@npm:7.2.3/minimatch": "^3.1.3",
@@ -116,8 +102,6 @@
116102
"nx@npm:19.6.4/minimatch": "^9.0.7",
117103
"webdriverio@npm:8.40.5/minimatch": "^9.0.7",
118104
"glob@npm:13.0.0/minimatch": "^10.2.3",
119-
"@sentry-internal/eslint-config-sdk@npm:10.45.0/@typescript-eslint/eslint-plugin": "^8.0.0",
120-
"@sentry-internal/eslint-config-sdk@npm:10.45.0/@typescript-eslint/parser": "^8.0.0",
121105
"eslint-plugin-ft-flow": "^3.0.0",
122106
"axios": "^1.13.5",
123107
"fast-xml-parser": "^5.5.7",

packages/core/.eslintignore

Lines changed: 0 additions & 8 deletions
This file was deleted.

packages/core/.eslintrc.js

Lines changed: 0 additions & 87 deletions
This file was deleted.

packages/core/.oxlintrc.json

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
{
2+
"$schema": "./node_modules/oxlint/configuration_schema.json",
3+
"plugins": ["typescript", "react", "import", "jsdoc"],
4+
"jsPlugins": [
5+
{
6+
"name": "sdk",
7+
"specifier": "@sentry-internal/eslint-plugin-sdk"
8+
}
9+
],
10+
"categories": {},
11+
"rules": {
12+
"no-unused-vars": [
13+
"warn",
14+
{ "argsIgnorePattern": "^_", "varsIgnorePattern": "^_", "caughtErrorsIgnorePattern": "^_" }
15+
],
16+
17+
// === Base rules from eslint-config-sdk/base.js ===
18+
"no-console": "error",
19+
"no-alert": "error",
20+
"no-param-reassign": "error",
21+
"prefer-template": "error",
22+
"no-bitwise": "error",
23+
"complexity": "error",
24+
"no-unused-expressions": ["error", { "allowShortCircuit": true }],
25+
"guard-for-in": "error",
26+
"array-callback-return": ["error", { "allowImplicit": true }],
27+
"quotes": ["error", "single", { "avoidEscape": true }],
28+
"no-return-await": "error",
29+
"max-lines": ["error", { "max": 300, "skipComments": true, "skipBlankLines": true }],
30+
31+
// === Import rules ===
32+
"import/namespace": "off",
33+
"import/no-unresolved": "off",
34+
35+
// === Rules turned off (not enforced in ESLint or causing false positives) ===
36+
"no-control-regex": "off",
37+
"jsdoc/check-tag-names": "off",
38+
"jsdoc/require-yields": "off",
39+
"no-shadow": "off",
40+
"no-unsafe-optional-chaining": "off",
41+
42+
// === Custom SDK rules (via JS plugin) ===
43+
"sdk/no-eq-empty": "error"
44+
},
45+
"overrides": [
46+
{
47+
"files": ["**/*.ts", "**/*.tsx", "**/*.d.ts"],
48+
"rules": {
49+
"typescript/ban-ts-comment": "error",
50+
"typescript/consistent-type-imports": "error",
51+
"typescript/no-unnecessary-type-assertion": "error",
52+
"typescript/prefer-for-of": "error",
53+
"typescript/explicit-function-return-type": ["error", { "allowExpressions": true }],
54+
"typescript/no-floating-promises": ["error", { "ignoreVoid": false }],
55+
"typescript/no-dynamic-delete": "error",
56+
"typescript/no-unsafe-member-access": "error",
57+
"typescript/unbound-method": "error",
58+
"typescript/no-explicit-any": "warn",
59+
"typescript/no-empty-function": "off",
60+
"typescript/no-empty-object-type": "off",
61+
"typescript/no-require-imports": "off",
62+
"typescript/prefer-optional-chain": "error",
63+
"typescript/no-unused-vars": ["error", { "argsIgnorePattern": "^_", "caughtErrors": "none" }],
64+
"typescript/no-redundant-type-constituents": "off",
65+
"typescript/restrict-template-expressions": "off",
66+
"typescript/no-base-to-string": "off"
67+
}
68+
},
69+
{
70+
"files": ["**/*.js", "**/*.mjs", "**/*.cjs"],
71+
"rules": {
72+
"typescript/ban-ts-comment": "off",
73+
"typescript/consistent-type-imports": "off",
74+
"typescript/prefer-optional-chain": "off",
75+
"typescript/no-unnecessary-type-assertion": "off",
76+
"typescript/prefer-for-of": "off",
77+
"typescript/no-floating-promises": "off",
78+
"typescript/no-dynamic-delete": "off",
79+
"typescript/no-unsafe-member-access": "off",
80+
"typescript/unbound-method": "off",
81+
"typescript/no-explicit-any": "off",
82+
"typescript/explicit-function-return-type": "off"
83+
}
84+
},
85+
{
86+
"files": [
87+
"**/*.test.ts",
88+
"**/*.test.tsx",
89+
"**/*.test.js",
90+
"**/*.test.jsx",
91+
"test/**/*.ts",
92+
"test/**/*.js"
93+
],
94+
"rules": {
95+
"typescript/explicit-function-return-type": "off",
96+
"typescript/no-empty-function": "off",
97+
"typescript/no-explicit-any": "off",
98+
"typescript/no-unsafe-member-access": "off",
99+
"typescript/no-floating-promises": "off",
100+
"typescript/no-non-null-assertion": "off",
101+
"typescript/unbound-method": "off",
102+
"no-unused-expressions": "off",
103+
"typescript/no-unused-expressions": "off",
104+
"max-lines": "off",
105+
"complexity": "off",
106+
"import/first": "off",
107+
"typescript/prefer-optional-chain": "off",
108+
"typescript/no-misused-spread": "off"
109+
}
110+
},
111+
{
112+
"files": ["*.tsx"],
113+
"rules": {
114+
"jsdoc/require-jsdoc": "off"
115+
}
116+
},
117+
{
118+
"files": ["scripts/*"],
119+
"rules": {
120+
"no-console": "off"
121+
}
122+
},
123+
{
124+
"files": ["**/src/**"],
125+
"rules": {
126+
"no-restricted-globals": ["error", "window", "document", "location", "navigator"],
127+
// Bundle size isn't a concern for React Native
128+
"sdk/no-class-field-initializers": "off",
129+
// TODO: Re-enable once oxlint supports inline disable for jsPlugin rules
130+
// Only 2 intentional uses exist (debugsymbolicator.ts, sentryMetroSerializer.ts)
131+
"sdk/no-regexp-constructor": "off"
132+
}
133+
}
134+
],
135+
"ignorePatterns": [
136+
"dist/**",
137+
"dangerfile.js",
138+
"RNSentryAndroidTester/**",
139+
"test/react-native/versions/**",
140+
"coverage/**",
141+
"test/typescript/**",
142+
"metro.d.ts",
143+
"plugin/build/**",
144+
"expo.d.ts",
145+
"playground.js",
146+
"playground.d.ts",
147+
"node_modules/**"
148+
]
149+
}

packages/core/package.json

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,11 @@
3737
"test:tools": "npx jest --config jest.config.tools.js",
3838
"test:watch": "npx jest --watch",
3939
"yalc:add:sentry-javascript": "yalc add @sentry/browser @sentry/core @sentry/react @sentry/types",
40-
"fix": "npx run-s fix:eslint fix:prettier",
41-
"fix:eslint": "ESLINT_USE_FLAT_CONFIG=false eslint --config .eslintrc.js --fix .",
40+
"fix": "npx run-s fix:oxlint fix:prettier",
41+
"fix:oxlint": "oxlint --fix",
4242
"fix:prettier": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --write \"{src,test,scripts,plugin/src}/**/**.ts\"",
43-
"lint": "npx run-s lint:eslint lint:prettier",
44-
"lint:eslint": "ESLINT_USE_FLAT_CONFIG=false eslint --config .eslintrc.js .",
43+
"lint": "npx run-s lint:oxlint lint:prettier",
44+
"lint:oxlint": "oxlint",
4545
"lint:prettier": "prettier --config ../../.prettierrc.json --ignore-path ../../.prettierignore --check \"{src,test,scripts,plugin/src}/**/**.ts\""
4646
},
4747
"bin": {
@@ -83,7 +83,6 @@
8383
"@expo/metro-config": "~0.20.0",
8484
"@mswjs/interceptors": "^0.25.15",
8585
"@react-native/babel-preset": "0.80.0",
86-
"@sentry-internal/eslint-config-sdk": "10.45.0",
8786
"@sentry-internal/eslint-plugin-sdk": "10.45.0",
8887
"@sentry-internal/typescript": "10.45.0",
8988
"@sentry/wizard": "6.12.0",
@@ -95,22 +94,18 @@
9594
"@types/uglify-js": "^3.17.2",
9695
"@types/uuid": "^9.0.4",
9796
"@types/xmlhttprequest": "^1.8.2",
98-
"@typescript-eslint/eslint-plugin": "^8.0.0",
99-
"@typescript-eslint/parser": "^8.0.0",
10097
"babel-jest": "^29.6.3",
10198
"babel-plugin-module-resolver": "^5.0.0",
10299
"babel-preset-fbjs": "^3.4.0",
103100
"downlevel-dts": "^0.11.0",
104-
"eslint": "^9.0.0",
105-
"eslint-plugin-react": "^7.37.0",
106-
"eslint-plugin-react-native": "^3.8.1",
107101
"expo": "^53.0.0",
108102
"expo-module-scripts": "3.1.0",
109103
"jest": "^29.6.3",
110104
"jest-environment-jsdom": "^29.6.2",
111105
"jest-extended": "^4.0.2",
112106
"madge": "^6.1.0",
113107
"metro": "0.83.1",
108+
"oxlint": "^1.56.0",
114109
"prettier": "^2.0.5",
115110
"react": "19.1.0",
116111
"react-native": "0.80.1",

packages/core/plugin/src/logger.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ const warningMap = new Map<string, boolean>();
77
export function warnOnce(message: string): void {
88
if (!warningMap.has(message)) {
99
warningMap.set(message, true);
10-
// eslint-disable-next-line no-console
10+
// oxlint-disable-next-line eslint(no-console)
1111
console.warn(yellow(prefix(message)));
1212
}
1313
}

packages/core/plugin/src/version.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
const packageJson: {
22
name: string;
33
version: string;
4-
// eslint-disable-next-line @typescript-eslint/no-var-requires
54
} = require('../../package.json');
65

76
export const PLUGIN_NAME = `${packageJson.name}/expo`;

packages/core/plugin/src/withSentry.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,6 @@ const missingAuthTokenMessage = '# Using SENTRY_AUTH_TOKEN environment variable'
6868

6969
export function getSentryProperties(props: PluginProps | void): string | null {
7070
const { organization, project, authToken, url = 'https://sentry.io/' } = props ?? {};
71-
// eslint-disable-next-line no-prototype-builtins
7271
const missingProperties = ['organization', 'project'].filter(each => !props?.hasOwnProperty(each));
7372

7473
if (missingProperties.length) {
@@ -111,7 +110,6 @@ function withSentryOptionsFile(config: ExpoConfig, pluginOptions: Record<string,
111110
return cfg;
112111
}
113112

114-
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
115113
const withSentry = createRunOncePlugin(withSentryPlugin, PLUGIN_NAME, PLUGIN_VERSION);
116114

117115
export { withSentry };

packages/core/plugin/src/withSentryIOS.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { ExpoConfig } from '@expo/config-types';
2-
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
32
import type { ConfigPlugin, XcodeProject } from 'expo/config-plugins';
43
import { withAppDelegate, withDangerousMod, withXcodeProject } from 'expo/config-plugins';
54
import * as path from 'path';
@@ -81,7 +80,6 @@ Run npx expo prebuild --clean`,
8180
export function addSentryWithBundledScriptsToBundleShellScript(script: string): string {
8281
return script.replace(
8382
/^.*?(packager|scripts)\/react-native-xcode\.sh\s*(\\'\\\\")?/m,
84-
// eslint-disable-next-line no-useless-escape
8583
(match: string) => `/bin/sh ${SENTRY_REACT_NATIVE_XCODE_PATH} ${match}`,
8684
);
8785
}

packages/core/scripts/eas-build-hook.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@
1919
* @see https://docs.sentry.io/platforms/react-native/
2020
*/
2121

22-
/* eslint-disable no-console */
23-
2422
const path = require('path');
2523
const fs = require('fs');
2624

0 commit comments

Comments
 (0)