Skip to content

Commit 8b9b033

Browse files
committedSep 26, 2023
fix: A new dependency "@jsenv/eslint-import-resolver" was added to tackle the issue of "import/no-useless-path-segments", "import/no-unused-modules" and some other import rules not working correctly.
Signed-off-by: prisis <d.bannert@anolilab.de>
1 parent fdbf6af commit 8b9b033

File tree

10 files changed

+165
-37
lines changed

10 files changed

+165
-37
lines changed
 

‎package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@
7777
"test:coverage:lint-staged-config": "pnpm --filter \"lint-staged-config\" run test:coverage",
7878
"test:coverage:package-json-utils": "pnpm --filter \"package-json-utils\" run test:coverage",
7979
"test:coverage:stylelint-config": "pnpm --filter \"stylelint-config\" run test:coverage",
80+
"test:eslint-config": "pnpm --filter \"eslint-config\" run test",
8081
"test:lint-staged-config": "pnpm --filter \"lint-staged-config\" run test",
8182
"test:package-json-utils": "pnpm --filter \"package-json-utils\" run test",
82-
"test:eslint-config": "pnpm --filter \"eslint-config\" run test",
8383
"test:stylelint": "node scripts/isNotWindows || stylelint --formatter verbose --config packages/stylelint-config/index.js ./packages/stylelint-config/__tests__/css/**/*.css",
8484
"test:stylelint-config": "pnpm --filter \"stylelint-config\" run test"
8585
},
@@ -107,9 +107,9 @@
107107
"cross-env": "^7.0.3",
108108
"cz-conventional-changelog": "^3.3.0",
109109
"eslint": "^8.50.0",
110+
"eslint-plugin-editorconfig": "^4.0.3",
110111
"eslint-plugin-etc": "^2.0.3",
111112
"eslint-plugin-vitest": "^0.3.1",
112-
"eslint-plugin-editorconfig": "^4.0.3",
113113
"eslint-plugin-vitest-globals": "^1.4.0",
114114
"husky": "^8.0.3",
115115
"is-ci": "^3.0.1",

‎packages/eslint-config/README.md

+39-7
Original file line numberDiff line numberDiff line change
@@ -52,15 +52,15 @@ To install this config, run the following command.
5252
> Note: `eslint-plugin-import@npm:eslint-plugin-i` is needed to use the correct package.
5353
5454
```bash
55-
npm install --save-dev eslint @anolilab/eslint-config eslint-plugin-import@npm:eslint-plugin-i@latest
55+
npm install --save-dev eslint @anolilab/eslint-config eslint-plugin-import@npm:eslint-plugin-i@latest @babel/core
5656
```
5757

5858
```sh
59-
pnpm add -D eslint @anolilab/eslint-config eslint-plugin-import@npm:eslint-plugin-i@latest
59+
pnpm add -D eslint @anolilab/eslint-config eslint-plugin-import@npm:eslint-plugin-i@latest @babel/core
6060
```
6161

6262
```sh
63-
yarn add -D eslint @anolilab/eslint-config eslint-plugin-import@npm:eslint-plugin-i@latest
63+
yarn add -D eslint @anolilab/eslint-config eslint-plugin-import@npm:eslint-plugin-i@latest @babel/core
6464
```
6565

6666
## Usage
@@ -112,7 +112,7 @@ For more advanced use cases see the example configurations for Node, TypeScript,
112112
### TypeScript
113113

114114
```bash
115-
npm install --save-dev eslint typescript @anolilab/eslint-config
115+
npm install --save-dev typescript
116116
```
117117

118118
Please extend the `.eslintrc.js` file with the correct `tsconfig.js` path if you have a custom path.
@@ -167,7 +167,11 @@ module.exports = defineConfig({
167167
You need to have "react" and "react-dom" installed.
168168

169169
```bash
170-
npm install --save-dev eslint eslint-plugin-react eslint-plugin-react-hooks @anolilab/eslint-config
170+
npm install --save-dev eslint-plugin-react eslint-plugin-react-hooks
171+
172+
yarn add -D eslint-plugin-react eslint-plugin-react-hooks
173+
174+
pnpm add -D eslint-plugin-react eslint-plugin-react-hooks
171175
```
172176

173177
Or for the use of `TypeScript` in react install "typescript" as a dev dependency.
@@ -182,10 +186,38 @@ module.exports = {
182186
};
183187
```
184188

189+
Or for the use of `.jsx` files install "@babel/plugin-syntax-jsx" as a dev dependency.
190+
191+
```bash
192+
npm install --save-dev babel @babel/plugin-syntax-jsx
193+
194+
yarn add -D babel @babel/plugin-syntax-jsx
195+
196+
pnpm add -D babel @babel/plugin-syntax-jsx
197+
```
198+
199+
In your `babel.config.js` file add the plugin.
200+
201+
```js
202+
const babelPluginSyntaxJSX = require("@babel/plugin-syntax-jsx");
203+
204+
module.exports = {
205+
plugins: [
206+
[
207+
babelPluginSyntaxJSX,
208+
{
209+
pragma: "React.createElement",
210+
pragmaFrag: "React.Fragment",
211+
},
212+
],
213+
],
214+
};
215+
```
216+
185217
### MDX
186218

187219
```bash
188-
npm install --save-dev eslint eslint-plugin-mdx @anolilab/eslint-config
220+
npm install --save-dev eslint eslint-plugin-mdx
189221
```
190222

191223
For more information about `missing` or `optional` to install rules see the `eslint` console output.
@@ -359,7 +391,7 @@ Of course, we also provide a recommended Prettier [configuration](../prettier-co
359391
If you are using experimental features such as class fields with JavaScript files you should install `@babel/eslint-parser`.
360392

361393
```bash
362-
npm install --save-dev @babel/core @babel/eslint-parser
394+
npm install --save-dev @babel/core
363395
```
364396

365397
## Plugins
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
#!/usr/bin/env node
2+
// eslint-disable-next-line import/extensions
23
require("../dist/postinstall");

‎packages/eslint-config/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@
175175
"devDependencies": {
176176
"@anolilab/semantic-release-preset": "7.0.3",
177177
"@arthurgeron/eslint-plugin-react-usememo": "^2.0.1",
178+
"@jsenv/eslint-import-resolver": "^8.0.2",
178179
"@testing-library/dom": "^9.3.3",
179180
"@total-typescript/ts-reset": "^0.5.1",
180181
"@types/confusing-browser-globals": "^1.0.1",

‎packages/eslint-config/src/config/plugins/html.ts

+4
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ const config: Linter.Config = {
3636
globals: {
3737
sourceCode: true,
3838
},
39+
env: {
40+
browser: true,
41+
node: false,
42+
},
3943
parser: "@html-eslint/parser",
4044
plugins: ["html", "@html-eslint"],
4145
rules: {

‎packages/eslint-config/src/config/plugins/import.ts

+28-17
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { fromRoot, hasTypescript, packageIsTypeModule } from "@anolilab/package-json-utils";
1+
import { fromRoot, packageIsTypeModule, projectPath } from "@anolilab/package-json-utils";
22
import type { Linter } from "eslint";
33

44
import { createConfigs } from "../../utils/create-config";
@@ -62,12 +62,14 @@ const config: Linter.Config = createConfigs([
6262
js: "always",
6363
jsx: "always",
6464
mjs: "always",
65+
json: "always",
6566
}
6667
: {
6768
cjs: "never",
6869
js: "never",
6970
jsx: "never",
7071
mjs: "never",
72+
json: "always",
7173
},
7274
],
7375

@@ -86,7 +88,11 @@ const config: Linter.Config = createConfigs([
8688
// deprecated: use `import/first`
8789
"import/imports-first": "off",
8890

89-
// Forbid modules to have too many dependencies
91+
// "import/max-dependencies" is not super useful
92+
// Either you will disable the eslint rule because it's "normal"
93+
// to have a lot of dependencies or feel compelled to reduce the number of imports.
94+
// It's already visible that a file has many imports and that ideally they should be
95+
// less imports, no need for ESLint, let's keep ESLint for more valuable things.
9096
// https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/max-dependencies.md
9197
"import/max-dependencies": ["off", { max: 10 }],
9298

@@ -283,8 +289,10 @@ const config: Linter.Config = createConfigs([
283289
"import/no-relative-packages": "error",
284290

285291
// Ensures that there are no useless path segments
292+
// TODO: Create a PR to fix commonjs option, when eslint --fix is run, it throws an error on the no-useless-path-segments.js:118
293+
// @see https://github.com/import-js/eslint-plugin-import/pull/2886
286294
// https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-useless-path-segments.md
287-
"import/no-useless-path-segments": ["error", { commonjs: !packageIsTypeModule, noUselessIndex: true }],
295+
"import/no-useless-path-segments": ["error", { commonjs: false, noUselessIndex: true }],
288296

289297
// Forbid Webpack loader syntax in imports
290298
// https://github.com/import-js/eslint-plugin-import/blob/main/docs/rules/no-webpack-loader-syntax.md
@@ -312,22 +320,22 @@ const config: Linter.Config = createConfigs([
312320
"import/extensions": [".js", ".cjs", ".mjs", ".jsx"],
313321
// Ensure consistent use of file extension within the import path
314322
"import/ignore": ["\\.(coffee|scss|css|less|hbs|svg|json)$"],
323+
},
324+
},
325+
type: "all",
326+
},
327+
{
328+
config: {
329+
settings: {
315330
"import/resolver": {
316-
node: {
317-
extensions: [".mjs", ".js", ".json", ".cjs", ".jsx"],
331+
"@jsenv/eslint-import-resolver": {
332+
rootDirectoryUrl: projectPath,
333+
packageConditions: ["node", "import"],
318334
},
319-
...(hasTypescript
320-
? {
321-
typescript: {
322-
alwaysTryTypes: true, // always try to resolve types under `<root>@types` directory even it doesn't contain any source code, like `@types/unist`
323-
project: fromRoot("tsconfig.json"),
324-
},
325-
}
326-
: {}),
327335
},
328336
},
329337
},
330-
type: "all",
338+
type: "javascript",
331339
},
332340
{
333341
config: {
@@ -347,8 +355,11 @@ const config: Linter.Config = createConfigs([
347355
js: "never",
348356
jsx: "never",
349357
mjs: "never",
358+
cjs: "never",
350359
ts: "never",
351360
tsx: "never",
361+
json: "always",
362+
svg: "always",
352363
},
353364
],
354365

@@ -372,10 +383,10 @@ const config: Linter.Config = createConfigs([
372383

373384
// Append 'ts' extensions to 'import/resolver' setting
374385
"import/resolver": {
375-
node: {
376-
extensions: [".mjs", ".cjs", ".js", ".json", ".ts", ".d.ts"],
386+
typescript: {
387+
alwaysTryTypes: true, // always try to resolve types under `<root>@types` directory even it doesn't contain any source code, like `@types/unist`
388+
project: fromRoot("tsconfig.json"),
377389
},
378-
typescript: true,
379390
},
380391
},
381392
},

‎packages/eslint-config/src/config/plugins/react.ts

+9-5
Original file line numberDiff line numberDiff line change
@@ -649,11 +649,6 @@ const config: Linter.Config = {
649649

650650
// View link below for react rules documentation
651651
settings: {
652-
"import/resolver": {
653-
node: {
654-
extensions: [".js", ".jsx", ".json", ".cjs", ".mjs"],
655-
},
656-
},
657652
propWrapperFunctions: [
658653
"forbidExtraProps", // https://www.npmjs.com/package/airbnb-prop-types
659654
"exact", // https://www.npmjs.com/package/prop-types-exact
@@ -669,6 +664,15 @@ const config: Linter.Config = {
669664
},
670665
{
671666
files: ["*.jsx"],
667+
parser: "@babel/eslint-parser",
668+
parserOptions: {
669+
ecmaFeatures: {
670+
jsx: true,
671+
},
672+
},
673+
settings: {
674+
extensions: [".jsx"],
675+
},
672676
rules: {
673677
// only .jsx files may have JSX
674678
// https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-tag-location.md

‎packages/eslint-config/src/config/plugins/unicorn.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { hasDependency, hasDevDependency, packageIsTypeModule } from "@anolilab/package-json-utils";
22
import type { Linter } from "eslint";
3-
import semver from "semver";
3+
import { gte } from "semver";
44

55
import indent from "../../utils/indent";
66

@@ -67,7 +67,7 @@ const config: Linter.Config = {
6767

6868
"unicorn/prefer-module": packageIsTypeModule ? "error" : "off",
6969

70-
"unicorn/prefer-node-protocol": semver.gte(process.version, "v16.0.0") ? "error" : "off",
70+
"unicorn/prefer-node-protocol": gte(process.version, "v16.0.0") ? "error" : "off",
7171

7272
// We only enforce it for single-line statements to not be too opinionated.
7373
"unicorn/prefer-ternary": ["error", "only-single-line"],

‎packages/eslint-config/src/index.ts

+38-4
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { join } from "node:path";
1717
import { hasDependency, hasDevDependency, packageIsTypeModule, pkg } from "@anolilab/package-json-utils";
1818
import type { Linter } from "eslint";
1919
import globals from "globals";
20-
import semver from "semver";
20+
import { intersects, rcompare } from "semver";
2121

2222
import { internalPluginConfig, pluginRules, possiblePluginRules, rules } from "./config";
2323
import engineRules from "./engine-node-overwrite";
@@ -77,6 +77,7 @@ if (!global.hasAnolilabEsLintConfigLoaded) {
7777
}
7878

7979
const configRules: Linter.RulesRecord = {};
80+
8081
let nodeVersion: string | undefined;
8182

8283
if (pkg?.engines?.["node"]) {
@@ -85,9 +86,9 @@ if (pkg?.engines?.["node"]) {
8586

8687
Object.entries(engineRules).forEach(([rule, ruleConfig]) => {
8788
Object.keys(ruleConfig)
88-
.sort(semver.rcompare)
89+
.sort(rcompare)
8990
.forEach((minVersion) => {
90-
if (nodeVersion && semver.intersects(nodeVersion, `<${minVersion}`)) {
91+
if (nodeVersion && intersects(nodeVersion, `<${minVersion}`)) {
9192
// eslint-disable-next-line security/detect-object-injection
9293
configRules[rule] = ruleConfig[minVersion as keyof typeof ruleConfig] as Linter.RuleEntry;
9394
}
@@ -118,6 +119,14 @@ const config: Linter.Config = {
118119
globals: {
119120
...globals.browser,
120121
...globals.nodeBuiltin,
122+
...(packageIsTypeModule
123+
? {
124+
__dirname: "off",
125+
__filename: "off",
126+
exports: "off",
127+
require: "off",
128+
}
129+
: { __dirname: true, __filename: true, exports: true, require: true }),
121130
},
122131
ignorePatterns: [
123132
"!.*",
@@ -173,7 +182,7 @@ const config: Linter.Config = {
173182
},
174183
// Fixes https://github.com/eslint/eslint/discussions/15305
175184
{
176-
files: packageIsTypeModule ? ["*.js", "*.mjs"] : ["*.mjs"],
185+
files: packageIsTypeModule ? ["**/*.js", "**/*.mjs"] : ["**/*.mjs"],
177186
parser: "@babel/eslint-parser",
178187
parserOptions: {
179188
babelOptions: {
@@ -182,6 +191,31 @@ const config: Linter.Config = {
182191
requireConfigFile: false,
183192
},
184193
},
194+
{
195+
env: {
196+
commonjs: true,
197+
},
198+
files: ["**/*.cjs"],
199+
// inside *.cjs files. restore commonJS "globals"
200+
globals: {
201+
__dirname: true,
202+
__filename: true,
203+
exports: true,
204+
require: true,
205+
},
206+
},
207+
{
208+
env: {
209+
commonjs: false,
210+
},
211+
files: ["**/*.mjs"],
212+
globals: {
213+
__dirname: "off",
214+
__filename: "off",
215+
exports: "off",
216+
require: "off",
217+
},
218+
},
185219
],
186220
// Disable the parser by default
187221
parser: "",

‎pnpm-lock.yaml

+41
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)
Please sign in to comment.