@open-turo/eslint-config-react 14.0.1 → 15.0.0-pr-320.3.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:
package/README.md CHANGED
@@ -20,28 +20,24 @@ Install the package and all of its peer dependencies:
20
20
  npx install-peerdeps --dev @open-turo/eslint-config-react
21
21
  ```
22
22
 
23
- Then in your `.eslintrc` file, extend from the default configuration of this package, which is the recommended eslint
24
- configuration for our existing front-end projects.
23
+ ### [`eslint.config.js`](https://eslint.org/docs/latest/use/configure/configuration-files-new) (requires eslint>=v8.23.0)
25
24
 
26
- To use this config, just add to your `.eslintrc` the following:
25
+ ```js
26
+ const turoConfig = require("@open-turo/eslint-config-react");
27
27
 
28
+ module.exports = turoConfig();
28
29
  ```
29
- "extends": "@open-turo/eslint-config-typescript"
30
- ```
31
-
32
- ### Legacy preset
33
30
 
34
- There is a `legacy` preset that extends `@open-turo/eslint-config-typescript/legacy`. This only exists for backwards
35
- compatibility with existing projects. It is strongly recommended to use the standard preset.
31
+ ### **[.eslintrc](https://eslint.org/docs/latest/use/configure/configuration-files)** (legacy example)
36
32
 
37
- To use the `legacy` preset, update your `.eslintrc` file to be:
38
-
39
- ```json
33
+ ```jsonc
40
34
  {
41
- "extends": "@open-turo/eslint-config-react/legacy"
35
+ "extends": "@open-turo/eslint-config-react/recommended",
42
36
  }
43
37
  ```
44
38
 
39
+ You will have to set the `ESLINT_USE_FLAT_CONFIG` env var to true.
40
+
45
41
  ## Development
46
42
 
47
43
  ### Pre-commit
@@ -0,0 +1,49 @@
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 = turoConfig({ turo: { ignores: ["/lib"] } });
49
+ ```
@@ -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,112 @@
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
+ /**
11
+ *
12
+ * @param {object} options ESLint configuration options
13
+ * @param {object} options.turo ESLing configuration options for open-turo/eslint-config-typescript. See their documentation for available options.
14
+ * @returns Configuration Array
15
+ */
16
+ module.exports = (options = {}) =>
17
+ tseslint.config(
18
+ {
19
+ extends: turoConfig({
20
+ ...options.turo,
21
+ allowModules: [
22
+ "@jest/globals",
23
+ "@testing-library/dom",
24
+ "@testing-library/react",
25
+ "@testing-library/user-event",
26
+ "nock",
27
+ ].concat(options.turo?.allowModules ?? []),
28
+ }),
29
+ rules: {
30
+ /*
31
+ * Rules that significantly impact performance time of eslint, and are not
32
+ * necessarily relevant for react applications.
33
+ */
34
+ "sonarjs/aws-apigateway-public-api": "off",
35
+ "sonarjs/aws-ec2-rds-dms-public": "off",
36
+ "sonarjs/aws-iam-all-privileges": "off",
37
+ "sonarjs/aws-iam-privilege-escalation": "off",
38
+ "sonarjs/aws-iam-public-access": "off",
39
+ "sonarjs/aws-restricted-ip-admin-access": "off",
40
+ "sonarjs/jsx-no-useless-fragment": "off",
41
+ // Already covered with react/no-array-index-key
42
+ "sonarjs/no-array-index-key": "off",
43
+ // Already covered with react/no-unknown-property
44
+ "sonarjs/no-unknown-property": "off",
45
+ "sonarjs/no-unstable-nested-components": "off",
46
+ // Allow file names to match a component name
47
+ "unicorn/filename-case": "off",
48
+ },
49
+ },
50
+ {
51
+ extends: [
52
+ reactPlugin.configs.flat.recommended,
53
+ reactPlugin.configs.flat["jsx-runtime"],
54
+ jsxA11yPlugin.flatConfigs.recommended,
55
+ reactCompilerPlugin.configs.recommended,
56
+ ],
57
+ files: ["**/*.{jsx,tsx,mjsx,cjsx}"],
58
+ languageOptions: {
59
+ globals: {
60
+ ...globals.browser,
61
+ },
62
+ },
63
+ plugins: {
64
+ "react-hooks": reactHooksPlugin,
65
+ },
66
+ rules: {
67
+ ...reactHooksPlugin.configs.recommended.rules,
68
+ "jsx-a11y/anchor-is-valid": [
69
+ "warn",
70
+ {
71
+ specialLink: ["to"],
72
+ },
73
+ ],
74
+ /** ESLint plugin for the React Compiler, to enforce rules that make adopting it easier/more effective */
75
+ "react-compiler/react-compiler": [
76
+ "error",
77
+ {
78
+ environment: {
79
+ /**
80
+ * At the time of writing, `eslint-plugin-react-compiler` errors on ref usages in render paths. This rule is noisy,
81
+ * since it currently reports false positives. We can remove this in the future when the rule is more accurate.
82
+ * {@link https://github.com/facebook/react/pull/30843 PR that disables this rule in the default config}
83
+ */
84
+ validateRefAccessDuringRender: false,
85
+ },
86
+ },
87
+ ],
88
+ // don't force .jsx extension
89
+ "react/jsx-filename-extension": "off",
90
+ // In TS you must use the Fragment syntax instead of the shorthand
91
+ "react/jsx-fragments": "off",
92
+ // This allows props to be spread in JSX
93
+ "react/jsx-props-no-spreading": "off",
94
+ // ensure props are alphabetical
95
+ "react/jsx-sort-props": "error",
96
+ // Allow emotion css prop
97
+ "react/no-unknown-property": ["error", { ignore: ["css"] }],
98
+ // We don't need default props on TS components
99
+ "react/require-default-props": "off",
100
+ "react/sort-prop-types": "error",
101
+ // State initialization can be in the constructor or via class fields
102
+ "react/state-in-constructor": "off",
103
+ // This allows static properties to be placed within the class declaration
104
+ "react/static-property-placement": "off",
105
+ },
106
+ settings: {
107
+ react: {
108
+ version: "detect",
109
+ },
110
+ },
111
+ },
112
+ );
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.3.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
- };