-
Notifications
You must be signed in to change notification settings - Fork 109
feat(eslint): support eslint for ReactLynx #1274
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
63bcbee
ce23e61
0df8dc8
7a4871d
1c63b9f
8209889
5015c6b
4b3727f
8f3e648
9935b72
f1d5c70
2d5f233
2cb1a7d
2c9bceb
52714ac
11e4270
b187872
f3db9c3
1949847
b9edc80
9106933
2b0cba4
20d001b
93de49f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "create-rspeedy": patch | ||
| --- | ||
|
|
||
| Support eslint for ReactLynx template | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "@lynx-js/eslint-config-reactlynx": patch | ||
| --- | ||
|
|
||
| Add new `@lynx-js/eslint-config-reactlynx` package for ESLint configuration |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import configs from '@lynx-js/eslint-config-reactlynx/ts'; | ||
|
|
||
| export default [ | ||
| ...configs, | ||
| { | ||
| files: ['src/**/*.{js,jsx,ts,tsx}'], | ||
| ignores: ['dist/'], | ||
| }, | ||
| ]; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| MIT License | ||
|
|
||
| Copyright (c) 2020-present The Preact Authors | ||
| Copyright (c) 2025 Lynx Authors. | ||
|
|
||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||
| of this software and associated documentation files (the "Software"), to deal | ||
| in the Software without restriction, including without limitation the rights | ||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the Software is | ||
| furnished to do so, subject to the following conditions: | ||
|
|
||
| The above copyright notice and this permission notice shall be included in all | ||
| copies or substantial portions of the Software. | ||
|
|
||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
| SOFTWARE. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| # @lynx-js/eslint-config-reactlynx | ||
|
|
||
| An unopinionated baseline ESLint configuration for ReactLynx codebases. This is based on the [eslint-config-preact](https://github.com/preactjs/eslint-config-preact) package. | ||
|
|
||
| ## Usage | ||
|
|
||
| Install eslint and this config: | ||
|
|
||
| ``` | ||
| npm i -D eslint @lynx-js/eslint-config-reactlynx | ||
| ``` | ||
|
|
||
| Then you need to configure it in `eslint.config.js`. | ||
|
|
||
| In TS project, you can use this config like this: | ||
|
|
||
| ```ts | ||
| import configs from '@lynx-js/eslint-config-reactlynx/ts'; | ||
|
|
||
| export default [ | ||
| ...configs, | ||
| { | ||
| files: ['src/**/*.{js,jsx,ts,tsx}'], | ||
| ignores: ['dist/'], | ||
| }, | ||
| ]; | ||
| ``` | ||
|
|
||
| In JS project, you can use this config like this: | ||
|
|
||
| ```js | ||
| import configs from '@lynx-js/eslint-config-reactlynx'; | ||
|
|
||
| export default [ | ||
| ...configs, | ||
| { | ||
| files: ['src/**/*.{js,jsx}'], | ||
| ignores: ['dist/'], | ||
| }, | ||
| ]; | ||
| ``` |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| { | ||
| "name": "@lynx-js/eslint-config-reactlynx", | ||
| "version": "0.0.0", | ||
| "description": "Unopinionated base ESLint configuration for ReactLynx projects.", | ||
| "keywords": [ | ||
| "react", | ||
| "lynx" | ||
| ], | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/lynx-family/lynx-stack.git", | ||
| "directory": "packages/eslint-config-reactlynx" | ||
| }, | ||
| "license": "MIT", | ||
| "type": "module", | ||
| "exports": { | ||
| ".": { | ||
| "types": "./lib/index.d.ts", | ||
| "default": "./lib/index.js" | ||
| }, | ||
| "./ts": { | ||
| "types": "./lib/ts.d.ts", | ||
| "default": "./lib/ts.js" | ||
| }, | ||
| "./package.json": "./package.json" | ||
| }, | ||
| "types": "index.d.ts", | ||
| "files": [ | ||
| "lib", | ||
| "LICENSE" | ||
| ], | ||
| "scripts": { | ||
| "test": "vitest", | ||
| "test:type": "vitest --typecheck.only" | ||
| }, | ||
| "dependencies": { | ||
| "@babel/eslint-parser": "^7.28.0", | ||
| "@babel/plugin-syntax-class-properties": "^7.12.13", | ||
| "@babel/plugin-syntax-jsx": "^7.27.1", | ||
| "@eslint/js": "^9.30.0", | ||
| "eslint-plugin-compat": "^6.0.2", | ||
| "eslint-plugin-react": "^7.37.5", | ||
| "eslint-plugin-react-hooks": "^5.2.0", | ||
| "globals": "^16.2.0", | ||
| "typescript-eslint": "^8.35.1" | ||
| }, | ||
| "devDependencies": { | ||
| "eslint": "^9.30.0" | ||
| }, | ||
| "peerDependencies": { | ||
| "eslint": "^8.57.1 || ^9.0.0" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,160 @@ | ||
| // Copyright 2025 The Lynx Authors. All rights reserved. | ||
| // Licensed under the MIT license that can be found in the | ||
| // LICENSE file in the root directory of this source tree. | ||
|
|
||
| import * as parser from '@babel/eslint-parser'; | ||
| import js from '@eslint/js'; | ||
| import type { Linter } from 'eslint'; | ||
| import { defineConfig } from 'eslint/config'; | ||
| import compat from 'eslint-plugin-compat'; | ||
| import react from 'eslint-plugin-react'; | ||
| import reactHooks from 'eslint-plugin-react-hooks'; | ||
| import knownGlobals from 'globals'; | ||
|
|
||
| const configs: Linter.Config<Linter.RulesRecord>[] = defineConfig([ | ||
|
Check failure on line 14 in packages/eslint-config-reactlynx/src/index.ts
|
||
upupming marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| { | ||
| extends: [ | ||
| js.configs.recommended, | ||
| ], | ||
| languageOptions: { | ||
| // TODO: this is really only required for class property initializer methods, which are seeing declining usage. | ||
| // At some point, we should un-ship the custom parser and let ESLint use esprima. | ||
| parser: parser as unknown as Linter.Parser, | ||
| // Currently ignored due to the custom parser. | ||
| parserOptions: { | ||
| ecmaVersion: 2020, | ||
| sourceType: 'module', | ||
| ecmaFeatures: { | ||
| modules: true, | ||
| impliedStrict: true, | ||
| jsx: true, | ||
| }, | ||
| requireConfigFile: false, | ||
| babelOptions: { | ||
| plugins: [ | ||
| '@babel/plugin-syntax-class-properties', | ||
| '@babel/plugin-syntax-jsx', | ||
| ], | ||
| }, | ||
| }, | ||
| globals: { | ||
| ...knownGlobals.browser, | ||
| ...knownGlobals.es2015, | ||
| ...knownGlobals.node, | ||
| expect: true, | ||
| browser: true, | ||
| global: true, | ||
| }, | ||
| }, | ||
| plugins: { | ||
| compat, | ||
|
Check failure on line 50 in packages/eslint-config-reactlynx/src/index.ts
|
||
| react, | ||
|
Check failure on line 51 in packages/eslint-config-reactlynx/src/index.ts
|
||
| 'react-hooks': reactHooks, | ||
|
Check failure on line 52 in packages/eslint-config-reactlynx/src/index.ts
|
||
| }, | ||
upupming marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| settings: { | ||
| // Preact CLI provides these defaults | ||
| targets: ['last 2 versions'], | ||
| polyfills: ['fetch', 'Promise'], | ||
| react: { | ||
| // eslint-plugin-preact interprets this as "h.createElement", | ||
| // however we only care about marking h() as being a used variable. | ||
| pragma: 'h', | ||
| // We use "react 16.0" to avoid pushing folks to UNSAFE_ methods. | ||
| version: '16.0', | ||
| }, | ||
| }, | ||
| rules: { | ||
| /** | ||
| * Preact / JSX rules | ||
| */ | ||
| 'react/no-deprecated': 2, | ||
| 'react/react-in-jsx-scope': 0, // handled this automatically | ||
| 'react/display-name': [1, { ignoreTranspilerName: false }], | ||
| 'react/jsx-no-bind': [1, { | ||
| ignoreRefs: true, | ||
| allowFunctions: true, | ||
| allowArrowFunctions: true, | ||
| }], | ||
| 'react/jsx-no-comment-textnodes': 2, | ||
| 'react/jsx-no-duplicate-props': 2, | ||
| 'react/jsx-no-target-blank': 2, | ||
| 'react/jsx-no-undef': 2, | ||
| 'react/jsx-uses-react': 2, // debatable | ||
| 'react/jsx-uses-vars': 2, | ||
| 'react/jsx-key': [2, { checkFragmentShorthand: true }], | ||
| 'react/self-closing-comp': 2, | ||
| 'react/prefer-es6-class': 2, | ||
| 'react/prefer-stateless-function': 1, | ||
| 'react/require-render-return': 2, | ||
| 'react/no-danger': 1, | ||
| // Legacy APIs not supported in Preact: | ||
| 'react/no-did-mount-set-state': 2, | ||
| 'react/no-did-update-set-state': 2, | ||
| 'react/no-find-dom-node': 2, | ||
| 'react/no-is-mounted': 2, | ||
| 'react/no-string-refs': 2, | ||
|
|
||
| /** | ||
| * Hooks | ||
| */ | ||
| 'react-hooks/rules-of-hooks': 2, | ||
| 'react-hooks/exhaustive-deps': 1, | ||
|
|
||
| /** | ||
| * General JavaScript error avoidance | ||
| */ | ||
| 'constructor-super': 2, | ||
| 'no-caller': 2, | ||
| 'no-const-assign': 2, | ||
| 'no-delete-var': 2, | ||
| 'no-dupe-class-members': 2, | ||
| 'no-dupe-keys': 2, | ||
| 'no-duplicate-imports': 2, | ||
| 'no-else-return': 1, | ||
| 'no-empty-pattern': 0, | ||
| 'no-empty': 0, | ||
| 'no-iterator': 2, | ||
| 'no-lonely-if': 2, | ||
| 'no-multi-str': 1, | ||
| 'no-new-wrappers': 2, | ||
| 'no-proto': 2, | ||
| 'no-redeclare': 2, | ||
| 'no-shadow-restricted-names': 2, | ||
| 'no-shadow': 0, | ||
| 'no-this-before-super': 2, | ||
| 'no-undef-init': 2, | ||
| 'no-unneeded-ternary': 2, | ||
| 'no-unused-vars': [2, { | ||
| args: 'after-used', | ||
| ignoreRestSiblings: true, | ||
| }], | ||
| 'no-useless-call': 1, | ||
| 'no-useless-computed-key': 1, | ||
| 'no-useless-concat': 1, | ||
| 'no-useless-constructor': 1, | ||
| 'no-useless-escape': 1, | ||
| 'no-useless-rename': 1, | ||
| 'no-var': 1, | ||
| 'no-with': 2, | ||
|
|
||
| /** | ||
| * General JavaScript stylistic rules (disabled) | ||
| */ | ||
| strict: [2, 'never'], // assume type=module output (cli default) | ||
| 'object-shorthand': 1, | ||
| 'prefer-arrow-callback': 1, | ||
| 'prefer-rest-params': 1, | ||
| 'prefer-spread': 1, | ||
| 'prefer-template': 1, | ||
| quotes: [0, 'single', { | ||
| avoidEscape: true, | ||
| allowTemplateLiterals: true, | ||
| }], | ||
| radix: 1, // parseInt(x, 10) | ||
| 'unicode-bom': 2, | ||
| 'valid-jsdoc': 0, | ||
| }, | ||
| }, | ||
| ]); | ||
|
|
||
| export default configs; | ||
Uh oh!
There was an error while loading. Please reload this page.