Skip to content

Commit 79b4941

Browse files
alexeyr-ci2alexeyr
andauthored
Upgrade ESLint (#1713)
* Upgrade eslint-config-shakacode * Upgrade to ESLint 9 * Disable some unneeded rules * Auto-fixes * Enable ESLint on config files * Update Knip * Enable ESLint on generator templates --------- Co-authored-by: Alexey Romanov <alexey.v.romanov@gmail.com>
1 parent 264c412 commit 79b4941

Some content is hidden

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

46 files changed

+1641
-1369
lines changed

.eslintignore

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

.eslintrc

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

.github/workflows/lint-js-and-ruby.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ jobs:
8181
yarn run knip
8282
yarn run knip --production
8383
- name: Lint JS
84-
run: yarn start lint
84+
run: yarn run eslint --report-unused-disable-directives
8585
- name: Check formatting
8686
run: yarn start format.listDifferent
8787
- name: Type-check TypeScript

.github/workflows/package-js-tests.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ jobs:
3838
- name: Install Node modules with Yarn for renderer package
3939
run: |
4040
yarn install --no-progress --no-emoji
41-
yarn run eslint -v
4241
sudo yarn global add yalc
4342
- name: Run JS unit tests for Renderer package
4443
run: yarn test

.prettierignore

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,3 @@ spec/dummy/public
1717
.rubocop.yml
1818
# Intentionally invalid
1919
spec/react_on_rails/fixtures/i18n/locales_symbols/
20-
21-
# Weirdly, fixing this file creates linting errors, even though it shouldn't make a difference.
22-
# Resolve later when upgrading ESLint.
23-
.eslintrc

eslint.config.ts

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
import { globalIgnores } from 'eslint/config';
2+
import prettierRecommended from 'eslint-plugin-prettier/recommended';
3+
import globals from 'globals';
4+
import tsEslint from 'typescript-eslint';
5+
import js from '@eslint/js';
6+
import { FlatCompat } from '@eslint/eslintrc';
7+
8+
const compat = new FlatCompat({
9+
baseDirectory: __dirname,
10+
recommendedConfig: js.configs.recommended,
11+
allConfig: js.configs.all,
12+
});
13+
14+
const config = tsEslint.config([
15+
globalIgnores([
16+
// compiled code
17+
'node_package/lib/',
18+
// used for tests only
19+
'spec/react_on_rails/dummy-for-generators',
20+
// temporary and generated files
21+
'spec/dummy/.yalc',
22+
'spec/dummy/public',
23+
'spec/dummy/vendor',
24+
'spec/dummy/tmp',
25+
'spec/dummy/app/assets/config/manifest.js',
26+
'spec/dummy/client/app/packs/server-bundle.js',
27+
'**/*.res.js',
28+
'**/coverage',
29+
'**/assets/webpack/**/*',
30+
'**/public/webpack/**/*',
31+
'**/generated/**/*',
32+
'**/app/assets/javascripts/application.js',
33+
'**/cable.js',
34+
'**/public/packs*/*',
35+
'**/gen-examples/',
36+
'**/bundle/',
37+
// dependencies
38+
'**/node_modules/**/*',
39+
]),
40+
{
41+
files: ['**/*.[jt]s', '**/*.[jt]sx', '**/*.[cm][jt]s'],
42+
},
43+
js.configs.recommended,
44+
compat.extends('eslint-config-shakacode'),
45+
{
46+
languageOptions: {
47+
globals: {
48+
...globals.browser,
49+
...globals.node,
50+
...globals.mocha,
51+
...globals.jest,
52+
__DEBUG_SERVER_ERRORS__: true,
53+
__SERVER_ERRORS__: true,
54+
},
55+
56+
parserOptions: {
57+
requireConfigFile: false,
58+
59+
babelOptions: {
60+
presets: ['@babel/preset-env', '@babel/preset-react'],
61+
},
62+
},
63+
},
64+
65+
settings: {
66+
'import/core-modules': ['react-redux'],
67+
68+
'import/resolver': {
69+
alias: [['Assets', './spec/dummy/client/app/assets']],
70+
71+
node: {
72+
extensions: ['.js', '.jsx', '.ts', '.d.ts'],
73+
},
74+
},
75+
},
76+
77+
rules: {
78+
'no-shadow': 'off',
79+
'no-console': 'off',
80+
'function-paren-newline': 'off',
81+
'object-curly-newline': 'off',
82+
'no-restricted-syntax': ['error', 'SequenceExpression'],
83+
84+
'import/extensions': [
85+
'error',
86+
'ignorePackages',
87+
{
88+
js: 'never',
89+
jsx: 'never',
90+
ts: 'never',
91+
},
92+
],
93+
94+
'import/first': 'off',
95+
'import/no-extraneous-dependencies': 'off',
96+
// The rule seems broken: it's reporting errors on imports in files using `export` too,
97+
// not just `module.exports`.
98+
'import/no-import-module-exports': 'off',
99+
'import/no-unresolved': [
100+
'error',
101+
{
102+
ignore: ['\\.res\\.js$'],
103+
},
104+
],
105+
'react/destructuring-assignment': [
106+
'error',
107+
'always',
108+
{
109+
ignoreClassFields: true,
110+
},
111+
],
112+
'react/forbid-prop-types': 'off',
113+
'react/function-component-definition': [
114+
'error',
115+
{
116+
namedComponents: ['arrow-function', 'function-declaration'],
117+
unnamedComponents: 'arrow-function',
118+
},
119+
],
120+
'react/jsx-props-no-spreading': 'off',
121+
'react/static-property-placement': 'off',
122+
'jsx-a11y/anchor-is-valid': 'off',
123+
},
124+
},
125+
{
126+
files: ['lib/generators/react_on_rails/templates/**/*'],
127+
rules: {
128+
// It doesn't use package.json from the template
129+
'import/no-unresolved': 'off',
130+
// We have `const [name, setName] = useState(props.name)` so can't just destructure props
131+
'react/destructuring-assignment': 'off',
132+
},
133+
},
134+
{
135+
files: ['**/*.ts', '**/*.tsx'],
136+
137+
extends: tsEslint.configs.recommended,
138+
139+
languageOptions: {
140+
parserOptions: {
141+
projectService: {
142+
allowDefaultProject: ['eslint.config.ts', 'knip.ts'],
143+
},
144+
},
145+
},
146+
147+
rules: {
148+
'@typescript-eslint/no-namespace': 'off',
149+
'@typescript-eslint/no-shadow': 'error',
150+
'@typescript-eslint/no-unused-vars': [
151+
'error',
152+
{
153+
caughtErrorsIgnorePattern: '^_',
154+
},
155+
],
156+
},
157+
},
158+
// must be the last config in the array
159+
// https://github.com/prettier/eslint-plugin-prettier?tab=readme-ov-file#configuration-new-eslintconfigjs
160+
prettierRecommended,
161+
]);
162+
163+
export default config;

knip.ts

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ const config: KnipConfig = {
1010
'node_package/src/registerServerComponent/client.ts!',
1111
'node_package/src/registerServerComponent/server.ts!',
1212
'node_package/src/RSCClientRoot.ts!',
13+
'eslint.config.ts',
1314
],
1415
project: ['node_package/src/**/*.[jt]s{x,}!', 'node_package/tests/**/*.[jt]s{x,}'],
1516
babel: {
@@ -27,10 +28,17 @@ const config: KnipConfig = {
2728
'@types/turbolinks',
2829
// The Knip ESLint plugin fails to detect these are transitively required by a config,
2930
// though we don't actually use its rules anywhere.
31+
'@babel/eslint-parser',
32+
'@babel/preset-react',
33+
'eslint-config-shakacode',
34+
'eslint-import-resolver-alias',
35+
'eslint-plugin-import',
3036
'eslint-plugin-jsx-a11y',
3137
'eslint-plugin-react',
32-
// Used in CI
33-
'@arethetypeswrong/cli',
38+
'eslint-plugin-react-hooks',
39+
// These are used as transitive dependencies and missing from package.json
40+
'@eslint/eslintrc',
41+
'@eslint/js',
3442
// used by Jest
3543
'jsdom',
3644
],

lib/generators/react_on_rails/templates/redux/base/app/javascript/bundles/HelloWorld/reducers/helloWorldReducer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { combineReducers } from 'redux';
22
import { HELLO_WORLD_NAME_UPDATE } from '../constants/helloWorldConstants';
33

4-
const name = (state = '', action) => {
4+
const name = (state = '', action = {}) => {
55
switch (action.type) {
66
case HELLO_WORLD_NAME_UPDATE:
77
return action.text;

node_package/src/CallbackRegistry.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,15 @@ type WaitingPromiseInfo<T> = {
1414

1515
export default class CallbackRegistry<T> {
1616
private readonly registryType: string;
17+
1718
private registeredItems = new Map<string, T>();
19+
1820
private waitingPromises = new Map<string, WaitingPromiseInfo<T>>();
21+
1922
private notUsedItems = new Set<string>();
2023

2124
private timeoutEventsInitialized = false;
25+
2226
private timedout = false;
2327

2428
constructor(registryType: string) {

node_package/src/ClientSideRenderer.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/* eslint-disable max-classes-per-file */
2+
/* eslint-disable react/no-deprecated -- while we need to support React 16 */
3+
14
import * as ReactDOM from 'react-dom';
25
import type { ReactElement } from 'react';
36
import type { RailsContext, RegisteredComponent, RenderFunction, Root } from './types';
@@ -40,8 +43,11 @@ const getDomId = (domIdOrElement: string | Element): string =>
4043
typeof domIdOrElement === 'string' ? domIdOrElement : domIdOrElement.getAttribute('data-dom-id') || '';
4144
class ComponentRenderer {
4245
private domNodeId: string;
46+
4347
private state: 'unmounted' | 'rendering' | 'rendered';
48+
4449
private root?: Root;
50+
4551
private renderPromise?: Promise<void>;
4652

4753
constructor(domIdOrElement: string | Element) {
@@ -166,6 +172,7 @@ You should return a React.Component always for the client side entry point.`);
166172

167173
class StoreRenderer {
168174
private hydratePromise?: Promise<void>;
175+
169176
private state: 'unmounted' | 'hydrating' | 'hydrated';
170177

171178
constructor(storeDataElement: Element) {

0 commit comments

Comments
 (0)