@open-turo/eslint-config-react 14.0.1 → 15.0.0-pr-320.2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,24 @@
1
+ name: Prerelease
2
+
3
+ on:
4
+ pull_request:
5
+ types:
6
+ - opened
7
+ - labeled
8
+ - synchronize
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+ jobs:
13
+ prerelease:
14
+ name: Prerelease
15
+ runs-on: ubuntu-latest
16
+ if: contains(github.event.pull_request.labels.*.name, 'prerelease')
17
+ steps:
18
+ - name: Prerelease
19
+ id: prerelease
20
+ uses: open-turo/actions-node/prerelease@v6
21
+ with:
22
+ github-token: ${{ secrets.OPEN_TURO_GITHUB_TOKEN }}
23
+ npm-token: ${{ secrets.OPEN_TURO_NPM_TOKEN }}
24
+ create-prerelease: true
package/.nvmrc CHANGED
@@ -1 +1 @@
1
- 22.13.1
1
+ 22.14.0
@@ -1,6 +1,6 @@
1
1
  repos:
2
2
  - repo: https://github.com/alessandrojcm/commitlint-pre-commit-hook
3
- rev: v9.20.0
3
+ rev: v9.21.0
4
4
  hooks:
5
5
  - id: commitlint
6
6
  stages: [commit-msg]
@@ -10,6 +10,7 @@ repos:
10
10
  hooks:
11
11
  - id: prettier
12
12
  stages: [commit]
13
+ additional_dependencies: ["prettier@3.5.2"]
13
14
  - repo: https://github.com/pre-commit/pre-commit-hooks
14
15
  rev: v5.0.0
15
16
  hooks:
@@ -0,0 +1,54 @@
1
+ # Breaking changes in v15
2
+
3
+ ## Minimum Node.js version
4
+
5
+ The minimum Node.js supported version is now `^20`.
6
+
7
+ ## Removed legacy preset
8
+
9
+ The legacy preset is removed, as it only existed for some internal turo projects. Maintaining it to support eslint v9
10
+ was not worth the effort.
11
+
12
+ ## Default flat configuration
13
+
14
+ The default configuration for this package is now a flat eslint configuration. Read the
15
+ eslint [guide](https://eslint.org/docs/latest/use/configure/migration-guide) for how to update legacy configurations
16
+ to flat configs.
17
+
18
+ The legacy configuration is still supported. To keep using it, you just have to update the `.eslintrc` file to:
19
+
20
+ ```diff
21
+ {
22
+ -- "extends": "@open-turo/eslint-config-react"
23
+ ++ "extends": "@open-turo/eslint-config-react/recommended"
24
+ }
25
+ ```
26
+
27
+ If you are using eslint v9, this also means that you will have to set the `ESLINT_USE_FLAT_CONFIG` env var to true.
28
+
29
+ ### Updating to flat configuration
30
+
31
+ If you wish to update to a flat configuration, you will have to make the following changes (please refer to the above guide
32
+ for all the details).
33
+
34
+ - Move from `.eslintrc` (or equivalent file) into `eslint.config.js` (or equivalent file).
35
+ - If you have a `.eslintignore` file, replace that into the `ignores` section of the `eslint.config.js` file
36
+
37
+ A `.eslintignore` file like this:
38
+
39
+ ```
40
+ /lib
41
+ ```
42
+
43
+ Will become a `eslint.config.js` file like this:
44
+
45
+ ```js
46
+ const turoConfig = require("@open-turo/eslint-config-react");
47
+
48
+ module.exports = [
49
+ ...turoConfig,
50
+ {
51
+ ignores: ["/lib"],
52
+ },
53
+ ];
54
+ ```
@@ -0,0 +1,4 @@
1
+ import openTuroConfig from "@open-turo/eslint-config-typescript";
2
+
3
+ // eslint-disable-next-line import/no-default-export
4
+ export default openTuroConfig({ typescript: false });
package/index.cjs ADDED
@@ -0,0 +1,104 @@
1
+ const turoConfig = require("@open-turo/eslint-config-typescript");
2
+ const jsxA11yPlugin = require("eslint-plugin-jsx-a11y");
3
+ const reactPlugin = require("eslint-plugin-react");
4
+ const reactCompilerPlugin = require("eslint-plugin-react-compiler");
5
+ const reactHooksPlugin = require("eslint-plugin-react-hooks");
6
+ const globals = require("globals");
7
+ // TODO We can't do this because this function is not here directly technically
8
+ const tseslint = require("typescript-eslint");
9
+
10
+ module.exports = tseslint.config(
11
+ {
12
+ extends: turoConfig({
13
+ allowModules: [
14
+ "@jest/globals",
15
+ "@testing-library/dom",
16
+ "@testing-library/react",
17
+ "@testing-library/user-event",
18
+ "nock",
19
+ ],
20
+ }),
21
+ rules: {
22
+ /*
23
+ * Rules that significantly impact performance time of eslint, and are not
24
+ * necessarily relevant for react applications.
25
+ */
26
+ "sonarjs/aws-apigateway-public-api": "off",
27
+ "sonarjs/aws-ec2-rds-dms-public": "off",
28
+ "sonarjs/aws-iam-all-privileges": "off",
29
+ "sonarjs/aws-iam-privilege-escalation": "off",
30
+ "sonarjs/aws-iam-public-access": "off",
31
+ "sonarjs/aws-restricted-ip-admin-access": "off",
32
+ "sonarjs/jsx-no-useless-fragment": "off",
33
+ // Already covered with react/no-array-index-key
34
+ "sonarjs/no-array-index-key": "off",
35
+ // Already covered with react/no-unknown-property
36
+ "sonarjs/no-unknown-property": "off",
37
+ "sonarjs/no-unstable-nested-components": "off",
38
+ // Allow file names to match a component name
39
+ "unicorn/filename-case": "off",
40
+ },
41
+ },
42
+ {
43
+ extends: [
44
+ reactPlugin.configs.flat.recommended,
45
+ reactPlugin.configs.flat["jsx-runtime"],
46
+ jsxA11yPlugin.flatConfigs.recommended,
47
+ reactCompilerPlugin.configs.recommended,
48
+ ],
49
+ files: ["**/*.{jsx,tsx,mjsx,cjsx}"],
50
+ languageOptions: {
51
+ globals: {
52
+ ...globals.browser,
53
+ },
54
+ },
55
+ plugins: {
56
+ "react-hooks": reactHooksPlugin,
57
+ },
58
+ rules: {
59
+ ...reactHooksPlugin.configs.recommended.rules,
60
+ "jsx-a11y/anchor-is-valid": [
61
+ "warn",
62
+ {
63
+ specialLink: ["to"],
64
+ },
65
+ ],
66
+ /** ESLint plugin for the React Compiler, to enforce rules that make adopting it easier/more effective */
67
+ "react-compiler/react-compiler": [
68
+ "error",
69
+ {
70
+ environment: {
71
+ /**
72
+ * At the time of writing, `eslint-plugin-react-compiler` errors on ref usages in render paths. This rule is noisy,
73
+ * since it currently reports false positives. We can remove this in the future when the rule is more accurate.
74
+ * {@link https://github.com/facebook/react/pull/30843 PR that disables this rule in the default config}
75
+ */
76
+ validateRefAccessDuringRender: false,
77
+ },
78
+ },
79
+ ],
80
+ // don't force .jsx extension
81
+ "react/jsx-filename-extension": "off",
82
+ // In TS you must use the Fragment syntax instead of the shorthand
83
+ "react/jsx-fragments": "off",
84
+ // This allows props to be spread in JSX
85
+ "react/jsx-props-no-spreading": "off",
86
+ // ensure props are alphabetical
87
+ "react/jsx-sort-props": "error",
88
+ // Allow emotion css prop
89
+ "react/no-unknown-property": ["error", { ignore: ["css"] }],
90
+ // We don't need default props on TS components
91
+ "react/require-default-props": "off",
92
+ "react/sort-prop-types": "error",
93
+ // State initialization can be in the constructor or via class fields
94
+ "react/state-in-constructor": "off",
95
+ // This allows static properties to be placed within the class declaration
96
+ "react/static-property-placement": "off",
97
+ },
98
+ settings: {
99
+ react: {
100
+ version: "detect",
101
+ },
102
+ },
103
+ },
104
+ );
package/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ // eslint-disable-next-line import/no-default-export
2
+ export { default } from "./index.cjs";
package/package.json CHANGED
@@ -1,37 +1,53 @@
1
1
  {
2
2
  "author": "Turo engineering",
3
3
  "description": "Turo eslint configuration for react",
4
+ "type": "module",
4
5
  "dependencies": {
5
- "@open-turo/eslint-config-typescript": "15.0.1",
6
+ "@open-turo/eslint-config-typescript": "16.0.0-pr-373.10.1.1",
6
7
  "eslint-plugin-jsx-a11y": "6.10.2",
7
8
  "eslint-plugin-react": "7.37.4",
8
- "eslint-plugin-react-compiler": "19.0.0-beta-e552027-20250112",
9
- "eslint-plugin-react-hooks": "5.1.0"
9
+ "eslint-plugin-react-compiler": "19.0.0-beta-30d8a17-20250209",
10
+ "eslint-plugin-react-hooks": "5.1.0",
11
+ "globals": "15.15.0",
12
+ "typescript-eslint": "8.23.0"
10
13
  },
11
14
  "devDependencies": {
12
- "eslint": "8.57.1",
13
- "prettier": "3.4.2"
15
+ "@types/react": "^19.0.10",
16
+ "eslint": "9.20.1",
17
+ "jest": "29.7.0",
18
+ "prettier": "3.5.2",
19
+ "react": "19.0.0"
14
20
  },
15
21
  "engines": {
16
- "node": ">= 18"
22
+ "node": ">= 20"
17
23
  },
18
24
  "homepage": "https://github.com/open-turo/eslint-config-react#readme",
19
25
  "license": "MIT",
20
- "main": "index.js",
26
+ "main": "index.cjs",
27
+ "module": "index.mjs",
21
28
  "scripts": {
22
29
  "build": "echo noop",
23
- "lint": "echo noop",
24
- "test": "echo noop"
30
+ "lint": "eslint './**/*.{cjs,mjs,js}'",
31
+ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js"
32
+ },
33
+ "exports": {
34
+ ".": {
35
+ "import": "./index.mjs",
36
+ "require": "./index.cjs",
37
+ "default": "./index.mjs"
38
+ },
39
+ "./recommended": {
40
+ "require": "./recommended.cjs"
41
+ }
25
42
  },
26
43
  "name": "@open-turo/eslint-config-react",
27
44
  "peerDependencies": {
28
- "eslint": ">=8.18.0",
45
+ "eslint": "^8.18.0 || ^9.0.0",
29
46
  "prettier": "^3.0.0"
30
47
  },
31
48
  "publishConfig": {
32
49
  "access": "public"
33
50
  },
34
51
  "repository": "https://github.com/open-turo/eslint-config-react",
35
- "version": "14.0.1",
36
- "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
52
+ "version": "15.0.0-pr-320.2.1.1"
37
53
  }
@@ -1,22 +1,23 @@
1
1
  module.exports = {
2
- root: true,
3
- plugins: ["react", "react-hooks", "jsx-a11y", "eslint-plugin-react-compiler"],
4
2
  env: {
5
3
  browser: true,
6
4
  },
7
- ignorePatterns: ["babel.config.js"],
8
5
  extends: [
9
- "@open-turo/eslint-config-typescript",
6
+ "@open-turo/eslint-config-typescript/recommended",
10
7
  "plugin:react/recommended",
11
8
  "plugin:react/jsx-runtime",
12
9
  "plugin:react-hooks/recommended",
13
10
  "plugin:jsx-a11y/recommended",
14
11
  ],
12
+ ignorePatterns: ["babel.config.js"],
15
13
  parserOptions: {
16
14
  ecmaFeatures: {
17
15
  jsx: true,
18
16
  },
17
+ jsxPragma: "React",
19
18
  },
19
+ plugins: ["react", "react-hooks", "jsx-a11y", "eslint-plugin-react-compiler"],
20
+ root: true,
20
21
  rules: {
21
22
  "jsx-a11y/anchor-is-valid": [
22
23
  "warn",
@@ -36,6 +37,20 @@ module.exports = {
36
37
  ],
37
38
  },
38
39
  ],
40
+ /** ESLint plugin for the React Compiler, to enforce rules that make adopting it easier/more effective */
41
+ "react-compiler/react-compiler": [
42
+ "error",
43
+ {
44
+ environment: {
45
+ /**
46
+ * At the time of writing, `eslint-plugin-react-compiler` errors on ref usages in render paths. This rule is noisy,
47
+ * since it currently reports false positives. We can remove this in the future when the rule is more accurate.
48
+ * {@link https://github.com/facebook/react/pull/30843 PR that disables this rule in the default config}
49
+ */
50
+ validateRefAccessDuringRender: false,
51
+ },
52
+ },
53
+ ],
39
54
  // don't force .jsx extension
40
55
  "react/jsx-filename-extension": "off",
41
56
  // In TS you must use the Fragment syntax instead of the shorthand
@@ -53,20 +68,6 @@ module.exports = {
53
68
  "react/state-in-constructor": "off",
54
69
  // This allows static properties to be placed within the class declaration
55
70
  "react/static-property-placement": "off",
56
- /** ESLint plugin for the React Compiler, to enforce rules that make adopting it easier/more effective */
57
- "react-compiler/react-compiler": [
58
- "error",
59
- {
60
- environment: {
61
- /**
62
- * At the time of writing, `eslint-plugin-react-compiler` errors on ref usages in render paths. This rule is noisy,
63
- * since it currently reports false positives. We can remove this in the future when the rule is more accurate.
64
- * {@link https://github.com/facebook/react/pull/30843 PR that disables this rule in the default config}
65
- */
66
- validateRefAccessDuringRender: false,
67
- },
68
- },
69
- ],
70
71
  /*
71
72
  * Rules that significantly impact performance time of eslint, and are not
72
73
  * necessarily relevant for react applications.
@@ -77,11 +78,11 @@ module.exports = {
77
78
  "sonarjs/aws-iam-privilege-escalation": "off",
78
79
  "sonarjs/aws-iam-public-access": "off",
79
80
  "sonarjs/aws-restricted-ip-admin-access": "off",
81
+ "sonarjs/jsx-no-useless-fragment": "off",
80
82
  // Already covered with react/no-array-index-key
81
83
  "sonarjs/no-array-index-key": "off",
82
84
  // Already covered with react/no-unknown-property
83
85
  "sonarjs/no-unknown-property": "off",
84
- "sonarjs/jsx-no-useless-fragment": "off",
85
86
  "sonarjs/no-unstable-nested-components": "off",
86
87
  // Allow file names to match a component name
87
88
  "unicorn/filename-case": "off",
@@ -0,0 +1,4 @@
1
+ /** @import { JSX } from "react"; */
2
+ export function Test() {
3
+ return <h1 className="test">Test</h1>;
4
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "compilerOptions": {
3
+ "allowJs": true,
4
+ "jsx": "react"
5
+ },
6
+ "include": ["./component.jsx"]
7
+ }
@@ -0,0 +1,61 @@
1
+ import { loadESLint } from "eslint";
2
+ import fs from "node:fs";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+
6
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
7
+
8
+ describe("validate config", () => {
9
+ const testFileName = "component.jsx";
10
+ const code = fs.readFileSync(
11
+ path.resolve(__dirname, "__fixtures__", testFileName),
12
+ "utf8",
13
+ );
14
+
15
+ test("the legacy recommended config is correct", async () => {
16
+ // Unlike the new flat config, the legacy turo config only works with TS, so we create a simple tsconfig.json file
17
+ // in the __fixtures__ directory to make it work
18
+ const ESLint = await loadESLint({
19
+ useFlatConfig: false,
20
+ });
21
+ const linter = new ESLint({
22
+ overrideConfig: {
23
+ parserOptions: {
24
+ tsconfigRootDir: path.resolve(__dirname, "__fixtures__"),
25
+ },
26
+ },
27
+ overrideConfigFile: "./recommended.cjs",
28
+ });
29
+ const messages = await linter.lintFiles(
30
+ path.resolve(__dirname, "__fixtures__", testFileName),
31
+ {
32
+ cwd: path.resolve(__dirname, "__fixtures__"),
33
+ },
34
+ );
35
+ expect(messages[0].messages).toEqual([]);
36
+ expect(messages[0].errorCount).toEqual(0);
37
+ });
38
+
39
+ test.each(["index.mjs", "index.cjs"])(
40
+ `the flat config is correct for %s`,
41
+ async (configFile) => {
42
+ const ESLint = await loadESLint({
43
+ useFlatConfig: true,
44
+ });
45
+ const { default: config } = await import(`../${configFile}`);
46
+ const linter = new ESLint({
47
+ baseConfig: config,
48
+ overrideConfig: [
49
+ {
50
+ files: [testFileName],
51
+ },
52
+ ],
53
+ });
54
+ const messages = await linter.lintText(code, {
55
+ filePath: testFileName,
56
+ });
57
+ expect(messages[0].messages).toEqual([]);
58
+ expect(messages[0].errorCount).toEqual(0);
59
+ },
60
+ );
61
+ });
package/legacy.js DELETED
@@ -1,75 +0,0 @@
1
- module.exports = {
2
- root: true,
3
- plugins: ["react", "react-hooks", "jsx-a11y"],
4
- env: {
5
- browser: true,
6
- },
7
- ignorePatterns: ["babel.config.js"],
8
- extends: [
9
- "@open-turo/eslint-config-typescript/legacy",
10
- "plugin:react/recommended",
11
- "plugin:react-hooks/recommended",
12
- "plugin:jsx-a11y/recommended",
13
- ],
14
- parserOptions: {
15
- ecmaFeatures: {
16
- jsx: true,
17
- },
18
- },
19
- rules: {
20
- "jsx-a11y/anchor-is-valid": [
21
- "warn",
22
- {
23
- specialLink: ["to"],
24
- },
25
- ],
26
- "n/no-unpublished-import": [
27
- "error",
28
- {
29
- allowModules: [
30
- "@jest/globals",
31
- "@testing-library/dom",
32
- "@testing-library/react",
33
- "@testing-library/user-event",
34
- "nock",
35
- ],
36
- },
37
- ],
38
- // don't force .jsx extension
39
- "react/jsx-filename-extension": "off",
40
- // In TS you must use the Fragment syntax instead of the shorthand
41
- "react/jsx-fragments": "off",
42
- // This allows props to be spread in JSX
43
- "react/jsx-props-no-spreading": "off",
44
- // ensure props are alphabetical
45
- "react/jsx-sort-props": "error",
46
- // We don't need default props on TS components
47
- "react/require-default-props": "off",
48
- "react/sort-prop-types": "error",
49
- // State initialization can be in the constructor or via class fields
50
- "react/state-in-constructor": "off",
51
- // This allows static properties to be placed within the class declaration
52
- "react/static-property-placement": "off",
53
- /**
54
- * Rules that significantly impact performance time of eslint, and are not
55
- * necessarily relevant for react applications.
56
- */
57
- "sonarjs/aws-apigateway-public-api": "off",
58
- "sonarjs/aws-ec2-rds-dms-public": "off",
59
- "sonarjs/aws-iam-all-privileges": "off",
60
- "sonarjs/aws-iam-privilege-escalation": "off",
61
- "sonarjs/aws-iam-public-access": "off",
62
- "sonarjs/aws-restricted-ip-admin-access": "off",
63
- // Already covered with react/no-array-index-key
64
- "sonarjs/no-array-index-key": "off",
65
- // Already covered with react/no-unknown-property
66
- "sonarjs/no-unknown-property": "off",
67
- "sonarjs/jsx-no-useless-fragment": "off",
68
- "sonarjs/no-unstable-nested-components": "off",
69
- },
70
- settings: {
71
- react: {
72
- version: "detect",
73
- },
74
- },
75
- };