Skip to content

Commit fcddab9

Browse files
feat!: update all rules and switch to eslint@9 (#30)
1 parent 7e99575 commit fcddab9

36 files changed

+9571
-7489
lines changed

.editorconfig

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,20 @@
1-
# editorconfig.org
1+
root = true
22

33
[*]
4-
indent_style = space
4+
indent_style = tab
55
indent_size = 2
66
end_of_line = lf
77
charset = utf-8
88
trim_trailing_whitespace = true
99
insert_final_newline = true
10+
max_line_length = 80
11+
12+
[*.{yml,yaml,json}]
13+
indent_style = space
14+
indent_size = 2
15+
16+
[*.md]
17+
trim_trailing_whitespace = false
18+
19+
[*.snap]
20+
trim_trailing_whitespace = false

.eslintrc.js

Lines changed: 0 additions & 4 deletions
This file was deleted.

.github/workflows/test.yml

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Test
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
11+
jobs:
12+
test:
13+
strategy:
14+
fail-fast: false
15+
matrix:
16+
os: [ubuntu-latest, windows-latest, macos-latest]
17+
node-version: [20.x, 22.x, 24.x]
18+
runs-on: ${{ matrix.os }}
19+
steps:
20+
- uses: actions/checkout@v4
21+
- name: Use Node.js ${{ matrix.node-version }}
22+
uses: actions/setup-node@v4
23+
with:
24+
node-version: ${{ matrix.node-version }}
25+
architecture: ${{ steps.calculate_architecture.outputs.result }}
26+
cache: "npm"
27+
- run: npm ci
28+
- run: npm run lint
29+
- uses: codecov/codecov-action@v5
30+
with:
31+
flags: integration
32+
token: ${{ secrets.CODECOV_TOKEN }}

.gitignore

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ pids
88
*.pid
99
*.seed
1010

11+
# IDE
12+
.idea
13+
1114
# Directory for instrumented libs generated by jscoverage/JSCover
1215
lib-cov
1316

@@ -28,10 +31,10 @@ build/Release
2831

2932
# Dependency directories
3033
node_modules
31-
jspm_packages
3234

33-
# Optional npm cache directory
35+
# Cache directories
3436
.npm
37+
.eslintcache
3538

3639
# Optional REPL history
3740
.node_repl_history

.prettierrc.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { default } from "./prettier-config.js";

README.md

Lines changed: 19 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
[![npm][npm]][npm-url]
22
[![test][test]][test-url]
3-
[![coverage][cover]][cover-url]
4-
[![chat][chat]][chat-url]
3+
[![discussions](https://img.shields.io/github/discussions/webpack/webpack)](https://github.com/webpack/webpack/discussions)
54

65
<div align="center">
76
<!-- replace with accurate logo e.g from https://worldvectorlogo.com/ -->
@@ -14,56 +13,32 @@
1413
<p>Provides Webpacks's .eslintrc as an extensible shared config.<p>
1514
</div>
1615

17-
<h2 align="center">Install</h2>
16+
# eslint-config-webpack
17+
18+
## Install
1819

1920
```bash
2021
npm i -D eslint-config-webpack
2122
```
2223

23-
<h2 align="center">Usage</h2>
24-
25-
Webpack's eslint config contains all of our ESLint rules, including ECMAScript 6+ and is similar to [Airbnb's ESLint base rules](https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb-base). It requires `eslint` and `eslint-plugin-import`.
24+
## Usage
2625

27-
<h2 align="center">eslint setup</h2>
26+
Webpack's eslint config contains all of our ESLint rules.
2827

29-
_In your .eslintrc.js || .yml || .json add ..._
28+
_In your eslint.config.js add ..._
3029

3130
```js
32-
// Add to your .eslintrc
33-
34-
"extends": "webpack"
31+
import { defineConfig } from "eslint/config";
32+
import config from "eslint-config-webpack";
33+
34+
export default defineConfig([
35+
{
36+
extends: [config]
37+
}
38+
]);
3539
```
3640

37-
<h2 align="center">Maintainers</h2>
38-
39-
<table>
40-
<tbody>
41-
<tr>
42-
<td align="center">
43-
<img width="150" height="150"
44-
src="https://avatars2.githubusercontent.com/u/8420490?v=3&s=150">
45-
</br>
46-
<a href="https://github.com/d3viant0ne">Joshua Wiens</a>
47-
</td>
48-
<td align="center">
49-
<img width="150" height="150"
50-
src="https://avatars3.githubusercontent.com/u/166921?v=3&s=150">
51-
</br>
52-
<a href="https://github.com/bebraw">Juho Vepsäläinen</a>
53-
</td>
54-
</tr>
55-
<tbody>
56-
</table>
57-
58-
59-
[npm]: https://img.shields.io/npm/v/@webpack-contrib/eslint-config-webpack.svg
60-
[npm-url]: https://npmjs.com/package/@webpack-contrib/eslint-config-webpack
61-
62-
[chat]: https://img.shields.io/badge/gitter-webpack%2Fwebpack-brightgreen.svg
63-
[chat-url]: https://gitter.im/webpack/webpack
64-
65-
[test]: http://img.shields.io/travis/webpack-contrib/eslint-config-webpack.svg
66-
[test-url]: https://travis-ci.org/webpack-contrib/eslint-config-webpack
67-
68-
[cover]: https://coveralls.io/repos/github/webpack-contrib/eslint-config-webpack/badge.svg?branch=master
69-
[cover-url]: https://coveralls.io/github/webpack-contrib/eslint-config-webpack?branch=master
41+
[npm]: https://img.shields.io/npm/v/eslint-config-webpack.svg
42+
[npm-url]: https://npmjs.com/package/eslint-config-webpack
43+
[test]: https://github.com/webpack-contrib/eslint-config-webpack/actions/workflows/test.yml/badge.svg
44+
[test-url]: https://github.com/webpack-contrib/eslint-config-webpack/actions/workflows/test.yml

configs.js

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
import fs from "node:fs";
2+
import path from "node:path";
3+
// eslint-disable-next-line import/no-unresolved
4+
import { globalIgnores } from "eslint/config";
5+
import semver from "semver";
6+
import configs from "./configs/index.js";
7+
import ignorePaths from "./ignore-paths.js";
8+
9+
const SKIP_TIME = 5000;
10+
11+
class Cache {
12+
/**
13+
* Initialize this cache instance.
14+
*/
15+
constructor() {
16+
this.map = new Map();
17+
}
18+
19+
/**
20+
* Get the cached value of the given key.
21+
* @param {string} key The key to get.
22+
* @returns {import('type-fest').JsonObject} The cached value or null.
23+
*/
24+
get(key) {
25+
const entry = this.map.get(key);
26+
const now = Date.now();
27+
28+
if (entry) {
29+
if (entry.expire > now) {
30+
entry.expire = now + SKIP_TIME;
31+
return entry.value;
32+
}
33+
this.map.delete(key);
34+
}
35+
return null;
36+
}
37+
38+
/**
39+
* Set the value of the given key.
40+
* @param {string} key The key to set.
41+
* @param {import('type-fest').JsonObject} value The value to set.
42+
* @returns {void}
43+
*/
44+
set(key, value) {
45+
const entry = this.map.get(key);
46+
const expire = Date.now() + SKIP_TIME;
47+
48+
if (entry) {
49+
entry.value = value;
50+
entry.expire = expire;
51+
} else {
52+
this.map.set(key, { value, expire });
53+
}
54+
}
55+
}
56+
57+
const cache = new Cache();
58+
59+
/**
60+
* Reads the `package.json` data in a given path.
61+
*
62+
* Don't cache the data.
63+
* @param {string} dir The path to a directory to read.
64+
* @returns {import('type-fest').JsonObject|null} The read `package.json` data, or null.
65+
*/
66+
function readPackageJson(dir) {
67+
const filePath = path.join(dir, "package.json");
68+
try {
69+
const text = fs.readFileSync(filePath, "utf8");
70+
const data = JSON.parse(text);
71+
72+
if (
73+
data !== null &&
74+
typeof data === "object" &&
75+
Array.isArray(data) === false
76+
) {
77+
data.filePath = filePath;
78+
return data;
79+
}
80+
// eslint-disable-next-line unicorn/prefer-optional-catch-binding
81+
} catch (_err) {
82+
// do nothing.
83+
}
84+
85+
return null;
86+
}
87+
88+
/**
89+
* Gets a `package.json` data.
90+
* The data is cached if found, then it's used after.
91+
* @param {string=} startPath A file path to lookup.
92+
* @returns {import('type-fest').JsonObject | null} A found `package.json` data or `null`.
93+
* This object have additional property `filePath`.
94+
*/
95+
function getPackageJson(startPath = "a.js") {
96+
const startDir = path.dirname(path.resolve(startPath));
97+
let dir = startDir;
98+
let prevDir = "";
99+
let data = null;
100+
101+
do {
102+
data = cache.get(dir);
103+
if (data) {
104+
if (dir !== startDir) {
105+
cache.set(startDir, data);
106+
}
107+
return data;
108+
}
109+
110+
data = readPackageJson(dir);
111+
if (data) {
112+
cache.set(dir, data);
113+
cache.set(startDir, data);
114+
return data;
115+
}
116+
117+
// Go to next.
118+
prevDir = dir;
119+
dir = path.resolve(dir, "..");
120+
} while (dir !== prevDir);
121+
122+
cache.set(startDir, null);
123+
return null;
124+
}
125+
126+
const packageJson = getPackageJson();
127+
const isModule =
128+
packageJson !== null &&
129+
typeof packageJson === "object" &&
130+
"type" in packageJson &&
131+
packageJson.type === "module";
132+
133+
/**
134+
* @returns {Record<string, string>} javascript configuration
135+
*/
136+
function getJavascriptConfig() {
137+
if (packageJson.engines && packageJson.engines.node) {
138+
const minVersion = semver.minVersion(packageJson.engines.node).major;
139+
140+
// https://node.green/
141+
switch (minVersion) {
142+
case 8:
143+
case 9:
144+
return configs["javascript/es2017"];
145+
case 10:
146+
case 11:
147+
return configs["javascript/es2018"];
148+
case 12:
149+
case 13: {
150+
const languageOptions = {
151+
...configs["javascript/es2019"].languageOptions,
152+
};
153+
154+
languageOptions.globals.Promise = false;
155+
languageOptions.globals.BigInt = false;
156+
157+
return { ...configs["javascript/es2019"], languageOptions };
158+
}
159+
case 14:
160+
return configs["javascript/es2020"];
161+
162+
case 15:
163+
return configs["javascript/es2021"];
164+
case 16:
165+
case 17:
166+
case 18:
167+
case 19:
168+
return configs["javascript/es2022"];
169+
case 20:
170+
case 21:
171+
return configs["javascript/es2023"];
172+
case 22:
173+
case 23:
174+
return configs["javascript/es2024"];
175+
case 24:
176+
case 25:
177+
return configs["javascript/es2025"];
178+
default:
179+
return configs["javascript/recommended"];
180+
}
181+
}
182+
183+
return configs["javascript/recommended"];
184+
}
185+
186+
configs.recommended = [
187+
globalIgnores(ignorePaths),
188+
isModule
189+
? configs["node/mixed-module-and-commonjs"]
190+
: configs["node/mixed-commonjs-and-module"],
191+
getJavascriptConfig(),
192+
configs["typescript/jsdoc"],
193+
configs["jest/recommended"],
194+
configs["markdown/recommended"],
195+
configs["stylistic/recommended"],
196+
];
197+
198+
configs["recommended-dirty"] = [
199+
globalIgnores(ignorePaths),
200+
configs["node/mixed-dirty"],
201+
getJavascriptConfig(),
202+
configs["typescript/jsdoc"],
203+
configs["jest/recommended"],
204+
configs["markdown/recommended"],
205+
configs["stylistic/recommended"],
206+
];
207+
208+
export { default } from "./configs/index.js";

configs/browser.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import globals from "globals";
2+
3+
const recommendedBrowserConfig = {
4+
languageOptions: {
5+
globals: {
6+
...globals.browser,
7+
}
8+
},
9+
};
10+
11+
export default {
12+
"browser/recommended": recommendedBrowserConfig,
13+
};

0 commit comments

Comments
 (0)