@cedarjs/eslint-config 0.0.4

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.
Files changed (5) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +74 -0
  3. package/index.js +142 -0
  4. package/package.json +44 -0
  5. package/shared.js +201 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Cedar
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,74 @@
1
+ # ESLint Config
2
+
3
+ <!-- toc -->
4
+
5
+ - [ESLint Config](#eslint-config)
6
+ - [Purpose and Vision](#purpose-and-vision)
7
+ - [Package Leads](#package-leads)
8
+ - [Roadmap](#roadmap)
9
+ - [Contributing](#contributing)
10
+ - [Overriding Default Configuration](#overriding-default-configuration)
11
+
12
+ ## Purpose and Vision
13
+
14
+ This package contains a shareable set of ESLint rules and configuration that can be re-used on all RedwoodJS projects. The framework [`eslint-config`](https://github.com/redwoodjs/redwood/tree/main/packages/eslint-config) package is used both for framework configuration and RedwoodJS app (created with the [CRWA](https://github.com/redwoodjs/redwood/tree/main/packages/create-cedar-app) package) configuration.
15
+
16
+ Our configuration uses recommended rule presets, including those from [ESLint](https://eslint.org/docs/rules/), [React](https://www.npmjs.com/package/eslint-plugin-react#list-of-supported-rules), the [Rules of Hooks](https://reactjs.org/docs/hooks-rules.html), and [Jest](https://github.com/testing-library/eslint-plugin-jest-dom#supported-rules). We also override the presets with some stylistic preferences. Some of them are:
17
+
18
+ - [No semicolons](https://eslint.org/docs/rules/semi) at the end of statements
19
+ - [Trailing commas](https://eslint.org/docs/rules/comma-dangle) in object and array literals
20
+ - [Use single quotes](https://eslint.org/docs/rules/quotes) on strings wherever possible
21
+ - [Use parentheses](https://eslint.org/docs/rules/arrow-parens) around arrow function parameters
22
+ - [Sort import declarations](https://eslint.org/docs/rules/sort-imports) by name
23
+ - [Wrap block statements](https://eslint.org/docs/rules/curly) in curly braces
24
+
25
+ ## Package Leads
26
+
27
+ Peter Pistorius (@peterp), David Price (@thedavidprice), Dominic Saadi (@jtoar), Daniel Choudhury (@dac09)
28
+
29
+ ## Roadmap
30
+
31
+ - Lint for case-sensitive imports (issue [#2806](https://github.com/redwoodjs/redwood/issues/2806))
32
+
33
+ ## Contributing
34
+
35
+ This package doesn't depend on other Redwood Framework packages. To contribute, you should be familiar with the ESLint package. Keep in mind that any rules added should not conflict with code formatting tools (e.g. [Prettier](https://prettier.io/docs/en/integrating-with-linters.html)).
36
+
37
+ ## Overriding Default Configuration
38
+
39
+ In a Redwood App, you can override default config in your root `package.json` file by adding the rules after the include for this package:
40
+
41
+ ```javascript
42
+ // redwood-app/package.json
43
+ "eslintConfig": {
44
+ "extends": "@redwoodjs/eslint-config",
45
+ "root": true,
46
+ "jsx-a11y/no-onchange": "off",
47
+ },
48
+ ```
49
+
50
+ If you need script in your configuration, you can remove the `eslintConfig` block from your root `package.json` file and add an `.eslintrc.js` file:
51
+
52
+ ```javascript
53
+ // redwood-app/.eslintrc.js
54
+ module.exports = {
55
+ extends: ['@redwoodjs/eslint-config'],
56
+ root: true,
57
+ rules: {
58
+ 'jsx-a11y/no-onchange': 'off',
59
+ },
60
+ }
61
+ ```
62
+
63
+ By default, ESLint will recurse through all project directories looking for configuration files and directives, and override those specified in multiple places according to a prioritization formula. The `root` directive tells ESLint to stop searching for configuration lower in the tree at the file this directive is encountered.
64
+
65
+ In a different Redwood Framework package or in a Redwood App, you can provide configuration that applies only to that package or side by omitting the `root` directive. For example, to apply a directive only to the client code of an app:
66
+
67
+ ```javascript
68
+ // e.g. redwood/packages/auth or redwood-app/web/package.json
69
+ "eslintConfig": {
70
+ "jsx-a11y/no-onchange": "off",
71
+ },
72
+ ```
73
+
74
+ In this case, ESLint will still load the configuration from the `@redwoodjs/eslint-config` package as the default value of `root` is `false`.
package/index.js ADDED
@@ -0,0 +1,142 @@
1
+ // This is the ESLint configuration used by Redwood projects.
2
+ // Shared eslint config (projects and framework) is located in ./shared.js
3
+ // Framework main config is in monorepo root ./.eslintrc.js
4
+
5
+ const {
6
+ getCommonPlugins,
7
+ getApiSideDefaultBabelConfig,
8
+ getWebSideDefaultBabelConfig,
9
+ } = require('@cedarjs/babel-config')
10
+ const { getConfig, isTypeScriptProject } = require('@cedarjs/project-config')
11
+
12
+ const config = getConfig()
13
+
14
+ const getProjectBabelOptions = () => {
15
+ // We can't nest the web overrides inside the overrides block
16
+ // So we just take it out and put it as a separate item
17
+ // Ignoring overrides, as I don't think it has any impact on linting
18
+ const { overrides: _webOverrides, ...otherWebConfig } =
19
+ getWebSideDefaultBabelConfig({
20
+ // We have to enable certain presets like `@babel/preset-react` for JavaScript projects
21
+ forJavaScriptLinting: !isTypeScriptProject(),
22
+ })
23
+
24
+ const { overrides: _apiOverrides, ...otherApiConfig } =
25
+ getApiSideDefaultBabelConfig()
26
+
27
+ return {
28
+ plugins: getCommonPlugins(),
29
+ overrides: [
30
+ {
31
+ test: ['./api/', './scripts/'],
32
+ ...otherApiConfig,
33
+ },
34
+ {
35
+ test: ['./web/'],
36
+ ...otherWebConfig,
37
+ },
38
+ ],
39
+ }
40
+ }
41
+
42
+ const plugins = []
43
+ const rules = {}
44
+
45
+ // Add react compiler plugin & rules if enabled
46
+ const reactCompilerEnabled =
47
+ config.experimental?.reactCompiler?.enabled ?? false
48
+ if (reactCompilerEnabled) {
49
+ plugins.push('react-compiler')
50
+ rules['react-compiler/react-compiler'] = 2
51
+ }
52
+
53
+ module.exports = {
54
+ extends: [
55
+ './shared.js',
56
+ config.web.a11y && 'plugin:jsx-a11y/recommended',
57
+ ].filter(Boolean),
58
+ // This is merged with `ignorePatterns` in shared.js
59
+ ignorePatterns: ['!.storybook/'],
60
+ parserOptions: {
61
+ requireConfigFile: false,
62
+ babelOptions: getProjectBabelOptions(),
63
+ },
64
+ plugins,
65
+ rules,
66
+ overrides: [
67
+ {
68
+ files: ['web/src/Routes.js', 'web/src/Routes.jsx', 'web/src/Routes.tsx'],
69
+ rules: {
70
+ 'no-undef': 'off',
71
+ 'jsx-a11y/aria-role': [
72
+ 2,
73
+ {
74
+ ignoreNonDOM: true,
75
+ },
76
+ ],
77
+ '@cedarjs/unsupported-route-components': 'error',
78
+ },
79
+ },
80
+ // `api` side
81
+ {
82
+ files: 'api/src/**',
83
+ env: {
84
+ node: true,
85
+ es6: true,
86
+ },
87
+ globals: {
88
+ gql: 'readonly',
89
+ context: 'readonly',
90
+ },
91
+ },
92
+ {
93
+ files: ['api/src/services/**/*.ts'],
94
+ plugins: ['@cedarjs'],
95
+ rules: {
96
+ '@cedarjs/service-type-annotations': 'off',
97
+ },
98
+ },
99
+ {
100
+ files: ['api/db/seed.js', 'scripts/**'],
101
+ env: {
102
+ node: true,
103
+ commonjs: true,
104
+ },
105
+ globals: {
106
+ Promise: 'readonly',
107
+ },
108
+ },
109
+ // `web` side
110
+ {
111
+ files: 'web/src/**',
112
+ env: {
113
+ browser: true,
114
+ es6: true,
115
+ 'shared-node-browser': true,
116
+ },
117
+ globals: {
118
+ React: 'readonly',
119
+ gql: 'readonly',
120
+ process: 'readonly',
121
+ require: 'readonly',
122
+ },
123
+ },
124
+ // Test, stories, scenarios, and mock files
125
+ {
126
+ files: [
127
+ '*.test.*',
128
+ '**/__mocks__/**',
129
+ '*.scenarios.*',
130
+ '*.stories.*',
131
+ '*.mock.*',
132
+ ],
133
+ globals: {
134
+ mockGraphQLQuery: 'readonly',
135
+ mockGraphQLMutation: 'readonly',
136
+ mockCurrentUser: 'readonly',
137
+ scenario: 'readonly',
138
+ defineScenario: 'readonly',
139
+ },
140
+ },
141
+ ],
142
+ }
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@cedarjs/eslint-config",
3
+ "version": "0.0.4",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/cedarjs/cedar.git",
7
+ "directory": "packages/eslint-config"
8
+ },
9
+ "license": "MIT",
10
+ "main": "index.js",
11
+ "scripts": {
12
+ "build": "echo 'Nothing to build..'",
13
+ "build:pack": "yarn pack -o cedar-eslint-config.tgz"
14
+ },
15
+ "dependencies": {
16
+ "@babel/core": "^7.26.10",
17
+ "@babel/eslint-parser": "7.25.7",
18
+ "@babel/eslint-plugin": "7.25.7",
19
+ "@cedarjs/eslint-plugin": "0.0.4",
20
+ "@cedarjs/internal": "0.0.4",
21
+ "@cedarjs/project-config": "0.0.4",
22
+ "@typescript-eslint/eslint-plugin": "8.19.1",
23
+ "@typescript-eslint/parser": "8.19.1",
24
+ "eslint": "8.57.1",
25
+ "eslint-config-prettier": "9.1.0",
26
+ "eslint-import-resolver-babel-module": "5.3.2",
27
+ "eslint-plugin-babel": "5.3.1",
28
+ "eslint-plugin-import": "2.30.0",
29
+ "eslint-plugin-jest-dom": "4.0.3",
30
+ "eslint-plugin-jsx-a11y": "6.10.2",
31
+ "eslint-plugin-prettier": "5.2.1",
32
+ "eslint-plugin-react": "7.36.1",
33
+ "eslint-plugin-react-hooks": "4.6.2",
34
+ "prettier": "3.5.3"
35
+ },
36
+ "devDependencies": {
37
+ "@babel/cli": "7.26.4",
38
+ "typescript": "5.6.2"
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "gitHead": "5b4f77f985bd86ee31ee7338312627accf0cb85b"
44
+ }
package/shared.js ADDED
@@ -0,0 +1,201 @@
1
+ // This ESLint configuration is shared between the Redwood framework,
2
+ // and Redwood projects.
3
+ //
4
+ // Our ESLint configuration is a mixture between ESLint's recommended
5
+ // rules [^1], React's recommended rules [^2], and a bit of our own stylistic
6
+ // flair:
7
+ // - no semicolons
8
+ // - comma dangle when multiline
9
+ // - single quotes
10
+ // - always use parenthesis around arrow functions
11
+ // - enforced import sorting
12
+ //
13
+ // [^1] https://eslint.org/docs/rules/
14
+ // [^2] https://www.npmjs.com/package/eslint-plugin-react#list-of-supported-rules
15
+
16
+ module.exports = {
17
+ extends: [
18
+ 'eslint:recommended',
19
+ 'plugin:react/recommended',
20
+ 'plugin:prettier/recommended',
21
+ 'plugin:jest-dom/recommended',
22
+ ],
23
+ // @NOTE parserOptions defined separately for project and framework
24
+ parser: '@babel/eslint-parser',
25
+ plugins: [
26
+ 'prettier',
27
+ '@babel',
28
+ 'import',
29
+ 'jsx-a11y',
30
+ 'react',
31
+ 'react-hooks',
32
+ 'jest-dom',
33
+ '@cedarjs',
34
+ ],
35
+ // In addition to this, eslint also has some implicit ignore patterns, like
36
+ // `node_modules`.
37
+ // See https://eslint.org/docs/latest/use/configure/ignore-deprecated
38
+ ignorePatterns: ['dist'],
39
+ settings: {
40
+ react: {
41
+ version: 'detect',
42
+ },
43
+ // For the import/order rule. Configures how it tells if an import is "internal" or not.
44
+ // An "internal" import is basically just one that's aliased.
45
+ //
46
+ // See...
47
+ // - https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/order.md#groups-array
48
+ // - https://github.com/import-js/eslint-plugin-import/blob/main/README.md#importinternal-regex
49
+ 'import/internal-regex': '^src/',
50
+ },
51
+ rules: {
52
+ '@cedarjs/process-env-computed': 'error',
53
+ 'prettier/prettier': 'warn',
54
+ 'no-console': 'off',
55
+ 'prefer-object-spread': 'warn',
56
+ 'prefer-spread': 'warn',
57
+ 'no-unused-expressions': [
58
+ 'error',
59
+ { allowShortCircuit: true, allowTernary: true },
60
+ ],
61
+ 'no-useless-escape': 'off',
62
+ camelcase: ['warn', { properties: 'never' }],
63
+ 'no-new': 'warn',
64
+ 'new-cap': ['error', { newIsCap: true, capIsNew: false }],
65
+ 'no-unused-vars': [
66
+ 'error',
67
+ { varsIgnorePattern: '^_', argsIgnorePattern: '^_' },
68
+ ],
69
+ // React rules
70
+ 'react/prop-types': 'off',
71
+ 'react/display-name': 'off',
72
+ 'react-hooks/exhaustive-deps': 'warn',
73
+ 'import/order': [
74
+ 'error',
75
+ {
76
+ 'newlines-between': 'always',
77
+ // We set this to an empty array to override the default value, which is `['builtin', 'external', 'object']`.
78
+ // Judging by the number of issues on the repo, this option seems to be notoriously tricky to understand.
79
+ // From what I can tell, if the value of this is `['builtin']` that means it won't sort builtins.
80
+ // But we have a rule for builtins below (react), so that's not what we want.
81
+ //
82
+ // See...
83
+ // - https://github.com/import-js/eslint-plugin-import/pull/1570
84
+ // - https://github.com/import-js/eslint-plugin-import/issues/1565
85
+ pathGroupsExcludedImportTypes: [],
86
+ // Only doing this to add internal. The order here maters.
87
+ // See https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/order.md#groups-array
88
+ groups: [
89
+ 'builtin',
90
+ 'external',
91
+ 'internal',
92
+ 'parent',
93
+ 'sibling',
94
+ 'index',
95
+ ],
96
+ pathGroups: [
97
+ {
98
+ pattern: 'react',
99
+ group: 'builtin',
100
+ position: 'after',
101
+ },
102
+ {
103
+ pattern: '@cedarjs/**',
104
+ group: 'external',
105
+ position: 'after',
106
+ },
107
+ {
108
+ // Matches...
109
+ // - src/directives/**/*.{js,ts}
110
+ // - src/services/**/*.{js,ts}
111
+ // - src/graphql/**/*.sdl.{js,ts}
112
+ //
113
+ // Uses https://github.com/isaacs/minimatch under the hood
114
+ // See https://github.com/isaacs/node-glob#glob-primer for syntax
115
+ pattern: 'src/*/**/*.?(sdl.){js,ts}',
116
+ patternOptions: {
117
+ nobrace: true,
118
+ noglobstar: true,
119
+ },
120
+ group: 'internal',
121
+ position: 'before',
122
+ },
123
+ ],
124
+ alphabetize: {
125
+ order: 'asc',
126
+ caseInsensitive: true,
127
+ },
128
+ },
129
+ ],
130
+ 'no-restricted-imports': [
131
+ 'error',
132
+ {
133
+ patterns: [
134
+ {
135
+ group: ['$api/*'],
136
+ message:
137
+ 'Importing from $api is only supported in *.routeHooks.{js,ts} files',
138
+ },
139
+ ],
140
+ },
141
+ ],
142
+ },
143
+ overrides: [
144
+ {
145
+ files: ['*.tsx', '*.js', '*.jsx'],
146
+ excludedFiles: ['api/src/**'],
147
+ rules: {
148
+ 'react-hooks/rules-of-hooks': 'error',
149
+ },
150
+ },
151
+ {
152
+ files: ['*.ts', '*.tsx'],
153
+ parser: '@typescript-eslint/parser',
154
+ extends: ['plugin:@typescript-eslint/recommended', 'prettier'],
155
+ rules: {
156
+ // TODO: look into enabling these eventually
157
+ '@typescript-eslint/no-empty-function': 'off',
158
+ '@typescript-eslint/prefer-function-type': 'off',
159
+
160
+ // Specific 'recommended' rules we alter
161
+ '@typescript-eslint/no-var-requires': 'off',
162
+ '@typescript-eslint/no-require-imports': 'off',
163
+ '@typescript-eslint/no-empty-object-type': 'off',
164
+ '@typescript-eslint/no-unused-vars': [
165
+ 'error',
166
+ { varsIgnorePattern: '^_', argsIgnorePattern: '^_' },
167
+ ],
168
+ },
169
+ },
170
+ {
171
+ files: ['*.test.*', '**/__mocks__/**'],
172
+ env: {
173
+ node: true,
174
+ es6: true,
175
+ commonjs: true,
176
+ jest: true,
177
+ },
178
+ },
179
+ {
180
+ files: [
181
+ '.babelrc.js',
182
+ 'babel.config.js',
183
+ '.eslintrc.js',
184
+ '*.config.js',
185
+ 'jest.setup.js',
186
+ ],
187
+ env: {
188
+ node: true,
189
+ commonjs: true,
190
+ jest: true,
191
+ },
192
+ },
193
+ {
194
+ files: [
195
+ 'web/src/**/*.routeHooks.{js,ts}',
196
+ 'web/src/entry.server.{jsx,tsx}',
197
+ ],
198
+ rules: { 'no-restricted-imports': 'off' },
199
+ },
200
+ ],
201
+ }