@eslint-umbrella/presets 1.1.2 → 1.1.3
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.
- package/.github/workflows/ci.yml +35 -9
- package/.github/workflows/{release.yml → publish.yml} +8 -18
- package/CHANGELOG.md +8 -1
- package/package.json +31 -21
- package/readme.md +8 -0
- package/src/base-typechecked.js +8 -0
- package/tests/fixtures/nest.ts +5 -0
- package/tests/fixtures/tsconfig.json +10 -0
- package/tests/fixtures/typechecked.ts +6 -0
- package/tests/presets.test.js +132 -0
package/.github/workflows/ci.yml
CHANGED
|
@@ -1,22 +1,48 @@
|
|
|
1
|
-
name:
|
|
1
|
+
name: CI
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
|
-
pull_request:
|
|
5
|
-
branches: [develop, maestro]
|
|
6
4
|
push:
|
|
7
|
-
branches:
|
|
5
|
+
branches:
|
|
6
|
+
- "**"
|
|
7
|
+
pull_request:
|
|
8
|
+
branches:
|
|
9
|
+
- "**"
|
|
10
|
+
workflow_dispatch:
|
|
11
|
+
|
|
12
|
+
concurrency:
|
|
13
|
+
group: ci-${{ github.ref }}
|
|
14
|
+
cancel-in-progress: true
|
|
8
15
|
|
|
9
16
|
permissions:
|
|
10
17
|
contents: read
|
|
11
18
|
|
|
12
19
|
jobs:
|
|
13
20
|
lint:
|
|
21
|
+
name: Lint (Node ${{ matrix.node-version }})
|
|
14
22
|
runs-on: ubuntu-latest
|
|
23
|
+
strategy:
|
|
24
|
+
fail-fast: false
|
|
25
|
+
matrix:
|
|
26
|
+
node-version: [20, 22]
|
|
15
27
|
steps:
|
|
16
|
-
-
|
|
17
|
-
|
|
28
|
+
- name: Checkout
|
|
29
|
+
uses: actions/checkout@v4
|
|
30
|
+
|
|
31
|
+
- name: Setup Node.js
|
|
32
|
+
uses: actions/setup-node@v4
|
|
18
33
|
with:
|
|
19
|
-
node-version:
|
|
34
|
+
node-version: ${{ matrix.node-version }}
|
|
20
35
|
cache: npm
|
|
21
|
-
|
|
22
|
-
-
|
|
36
|
+
|
|
37
|
+
- name: Install dependencies
|
|
38
|
+
run: |
|
|
39
|
+
node -v
|
|
40
|
+
npm -v
|
|
41
|
+
npm config list
|
|
42
|
+
npm ci
|
|
43
|
+
|
|
44
|
+
- name: Run lint (CI)
|
|
45
|
+
run: npm run lint:ci
|
|
46
|
+
|
|
47
|
+
- name: Run tests
|
|
48
|
+
run: npm test
|
|
@@ -2,12 +2,13 @@ name: release
|
|
|
2
2
|
|
|
3
3
|
on:
|
|
4
4
|
push:
|
|
5
|
-
branches: [
|
|
5
|
+
branches: [master]
|
|
6
6
|
workflow_dispatch: {}
|
|
7
7
|
|
|
8
8
|
permissions:
|
|
9
|
+
id-token: write
|
|
9
10
|
contents: write
|
|
10
|
-
pull-requests: write
|
|
11
|
+
pull-requests: write
|
|
11
12
|
|
|
12
13
|
jobs:
|
|
13
14
|
lint:
|
|
@@ -18,13 +19,13 @@ jobs:
|
|
|
18
19
|
with:
|
|
19
20
|
node-version: 20
|
|
20
21
|
cache: npm
|
|
21
|
-
- run: npm ci
|
|
22
|
+
- run: npm ci
|
|
22
23
|
- run: npm run lint:ci
|
|
24
|
+
- run: npm test
|
|
23
25
|
|
|
24
26
|
release:
|
|
25
27
|
needs: lint
|
|
26
28
|
runs-on: ubuntu-latest
|
|
27
|
-
environment: maestro
|
|
28
29
|
steps:
|
|
29
30
|
- uses: actions/checkout@v4
|
|
30
31
|
with:
|
|
@@ -35,20 +36,10 @@ jobs:
|
|
|
35
36
|
node-version: 20
|
|
36
37
|
cache: npm
|
|
37
38
|
registry-url: https://registry.npmjs.org
|
|
38
|
-
always-auth: true
|
|
39
39
|
|
|
40
|
-
- run: npm
|
|
40
|
+
- run: npm i -g npm@^11.5.1
|
|
41
41
|
|
|
42
|
-
-
|
|
43
|
-
run: |
|
|
44
|
-
echo "//registry.npmjs.org/:_authToken=${NPM_TOKEN}" > "$NPM_CONFIG_USERCONFIG"
|
|
45
|
-
echo "@eslint-umbrella:registry=https://registry.npmjs.org/" >> "$NPM_CONFIG_USERCONFIG"
|
|
46
|
-
echo "Configured auth in $NPM_CONFIG_USERCONFIG"
|
|
47
|
-
env:
|
|
48
|
-
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
49
|
-
|
|
50
|
-
- name: npm ping
|
|
51
|
-
run: npm ping
|
|
42
|
+
- run: npm ci
|
|
52
43
|
|
|
53
44
|
- uses: changesets/action@v1
|
|
54
45
|
with:
|
|
@@ -57,5 +48,4 @@ jobs:
|
|
|
57
48
|
createGithubReleases: true
|
|
58
49
|
env:
|
|
59
50
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
60
|
-
|
|
61
|
-
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
51
|
+
NPM_CONFIG_PROVENANCE: true
|
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eslint-umbrella/presets",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.3",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"description": "
|
|
5
|
+
"description": "Batteries-included ESLint flat config presets for React, Next.js, Express, NestJS, React Native, React-PDF, and TypeScript",
|
|
6
|
+
"license": "MIT",
|
|
6
7
|
"publishConfig": {
|
|
7
8
|
"access": "public"
|
|
8
9
|
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/Papitoulini/eslint-umbrella.git"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/Papitoulini/eslint-umbrella#readme",
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/Papitoulini/eslint-umbrella/issues"
|
|
17
|
+
},
|
|
18
|
+
"sideEffects": false,
|
|
9
19
|
"exports": {
|
|
10
20
|
".": "./src/index.js",
|
|
11
21
|
"./base": "./src/base.js",
|
|
@@ -17,38 +27,38 @@
|
|
|
17
27
|
"./react-native": "./src/react-native.js",
|
|
18
28
|
"./react-pdf": "./src/react-pdf.js"
|
|
19
29
|
},
|
|
20
|
-
"sideEffects": false,
|
|
21
30
|
"scripts": {
|
|
22
31
|
"lint": "eslint .",
|
|
23
32
|
"lint:fix": "eslint . --fix",
|
|
24
33
|
"lint:ci": "eslint . --max-warnings=0",
|
|
34
|
+
"test": "node --test",
|
|
25
35
|
"changeset": "changeset",
|
|
26
36
|
"version-packages": "changeset version && npm i --package-lock-only --ignore-scripts",
|
|
27
37
|
"release": "changeset publish"
|
|
28
38
|
},
|
|
29
|
-
"license": "MIT",
|
|
30
39
|
"dependencies": {
|
|
40
|
+
"@eslint/js": "^9.39.2",
|
|
31
41
|
"@next/eslint-plugin-next": "14.2.14",
|
|
32
|
-
"eslint-plugin
|
|
33
|
-
"eslint-plugin-
|
|
34
|
-
"eslint-plugin-react-hooks": "5.1.0",
|
|
35
|
-
"eslint-plugin-react-refresh": "0.4.12",
|
|
36
|
-
"eslint-plugin-security": "3.0.1",
|
|
37
|
-
"eslint-plugin-unused-imports": "4.1.4",
|
|
38
|
-
"globals": "^16.4.0",
|
|
39
|
-
"typescript": "5.6.3",
|
|
40
|
-
"typescript-eslint": "8.8.1",
|
|
42
|
+
"@stylistic/eslint-plugin": "^5.7.1",
|
|
43
|
+
"eslint-plugin-import": "^2.31.0",
|
|
41
44
|
"eslint-plugin-promise": "^7.2.1",
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"eslint-plugin-react-native": "^5.0.0"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
45
|
+
"eslint-plugin-react": "^7.37.5",
|
|
46
|
+
"eslint-plugin-react-hooks": "^5.1.0",
|
|
47
|
+
"eslint-plugin-react-native": "^5.0.0",
|
|
48
|
+
"eslint-plugin-react-refresh": "^0.4.12",
|
|
49
|
+
"eslint-plugin-security": "^3.0.1",
|
|
50
|
+
"eslint-plugin-unused-imports": "^4.1.4",
|
|
51
|
+
"globals": "^16.5.0",
|
|
52
|
+
"typescript": "5.6.3",
|
|
53
|
+
"typescript-eslint": "^8.8.1"
|
|
50
54
|
},
|
|
51
55
|
"peerDependencies": {
|
|
52
56
|
"eslint": "^9.0.0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@changesets/cli": "^2.29.7",
|
|
60
|
+
"eslint": "^9.39.2",
|
|
61
|
+
"@types/node": "^20.0.0",
|
|
62
|
+
"undici-types": "^7.16.0"
|
|
53
63
|
}
|
|
54
64
|
}
|
package/readme.md
CHANGED
|
@@ -187,6 +187,14 @@ export default [
|
|
|
187
187
|
|
|
188
188
|
> Do **not** delete pending `.changeset/*.md`; the version step consumes them automatically.
|
|
189
189
|
|
|
190
|
+
|
|
191
|
+
## 🔁 Publish flow (develop → master)
|
|
192
|
+
|
|
193
|
+
1. Ensure `develop` is green and up to date.
|
|
194
|
+
2. Open a PR from `develop` into `master`.
|
|
195
|
+
3. Run the release steps above in the PR branch (or let CI handle it).
|
|
196
|
+
4. Merge the PR after approvals; `master` is the published source of truth.
|
|
197
|
+
|
|
190
198
|
---
|
|
191
199
|
|
|
192
200
|
## 🤝 Contributing
|
package/src/base-typechecked.js
CHANGED
|
@@ -142,6 +142,14 @@ export default function baseTypeChecked(project = ["tsconfig.json"]) {
|
|
|
142
142
|
"error",
|
|
143
143
|
{ checksVoidReturn: { attributes: false } }
|
|
144
144
|
],
|
|
145
|
+
"@typescript-eslint/no-unused-expressions": [
|
|
146
|
+
"error",
|
|
147
|
+
{
|
|
148
|
+
allowShortCircuit: false,
|
|
149
|
+
allowTernary: false,
|
|
150
|
+
allowTaggedTemplates: false
|
|
151
|
+
}
|
|
152
|
+
],
|
|
145
153
|
"@typescript-eslint/no-unnecessary-condition": [
|
|
146
154
|
"warn",
|
|
147
155
|
{ allowConstantLoopConditions: true }
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import test from "node:test";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
import { ESLint } from "eslint";
|
|
7
|
+
|
|
8
|
+
import {
|
|
9
|
+
base,
|
|
10
|
+
baseTypeChecked,
|
|
11
|
+
express,
|
|
12
|
+
nest,
|
|
13
|
+
nestTypeChecked,
|
|
14
|
+
next,
|
|
15
|
+
react,
|
|
16
|
+
reactNative,
|
|
17
|
+
reactPdf
|
|
18
|
+
} from "../src/index.js";
|
|
19
|
+
|
|
20
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
21
|
+
const fixturesDir = path.join(__dirname, "fixtures");
|
|
22
|
+
const tsconfigPath = path.join(fixturesDir, "tsconfig.json");
|
|
23
|
+
|
|
24
|
+
const formatMessages = messages =>
|
|
25
|
+
messages
|
|
26
|
+
.map(message => `${message.ruleId ?? "unknown"}: ${message.message}`)
|
|
27
|
+
.join("\n");
|
|
28
|
+
|
|
29
|
+
const withTsconfigRoot = (config, tsconfigRootDir) => [
|
|
30
|
+
...config,
|
|
31
|
+
{ languageOptions: { parserOptions: { tsconfigRootDir } } }
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
async function lintText(config, code, { filename, cwd = process.cwd() } = {}) {
|
|
35
|
+
const eslint = new ESLint({
|
|
36
|
+
cwd,
|
|
37
|
+
overrideConfigFile: null,
|
|
38
|
+
overrideConfig: config,
|
|
39
|
+
ignore: false
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const results = await eslint.lintText(code, { filePath: path.join(cwd, filename) });
|
|
43
|
+
const errors = results.flatMap(result => result.messages.filter(message => message.severity === 2));
|
|
44
|
+
|
|
45
|
+
assert.equal(
|
|
46
|
+
errors.length,
|
|
47
|
+
0,
|
|
48
|
+
errors.length ? `Unexpected ESLint errors:\n${formatMessages(errors)}` : undefined
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
test("base preset lints a simple module", async () => {
|
|
53
|
+
await lintText(
|
|
54
|
+
base(),
|
|
55
|
+
"const value = 1; export default value;",
|
|
56
|
+
{ filename: "base.js" }
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
test("react preset lints JSX", async () => {
|
|
61
|
+
await lintText(
|
|
62
|
+
react(),
|
|
63
|
+
"const App = () => <div />; export default App;",
|
|
64
|
+
{ filename: "component.jsx" }
|
|
65
|
+
);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("next preset lints a page component", async () => {
|
|
69
|
+
await lintText(
|
|
70
|
+
next(),
|
|
71
|
+
"export default function Page() { return <div />; }",
|
|
72
|
+
{ filename: "page.jsx" }
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
test("express preset lints a basic app", async () => {
|
|
77
|
+
await lintText(
|
|
78
|
+
express(),
|
|
79
|
+
"import express from \"express\"; const app = express(); app.get(\"/\", (req, res) => { res.send(\"ok\"); }); export default app;",
|
|
80
|
+
{ filename: "server.js" }
|
|
81
|
+
);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("nest preset lints a service class", async () => {
|
|
85
|
+
await lintText(
|
|
86
|
+
nest(),
|
|
87
|
+
"export class ExampleService { getValue() { return 1; } }",
|
|
88
|
+
{ filename: "service.ts" }
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("react-native preset lints a component", async () => {
|
|
93
|
+
await lintText(
|
|
94
|
+
reactNative(),
|
|
95
|
+
"import { StyleSheet, View } from \"react-native\"; const styles = StyleSheet.create({ container: { flex: 1 } }); const App = () => <View style={styles.container} />; export default App;",
|
|
96
|
+
{ filename: "app.jsx" }
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("react-pdf preset lints a hook-based component", async () => {
|
|
101
|
+
await lintText(
|
|
102
|
+
reactPdf(),
|
|
103
|
+
"import { useEffect } from \"react\"; export default function Doc() { useEffect(() => {}, []); return null; }",
|
|
104
|
+
{ filename: "doc.jsx" }
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("base type-checked preset lints TS", async () => {
|
|
109
|
+
await lintText(
|
|
110
|
+
withTsconfigRoot(baseTypeChecked([tsconfigPath]), fixturesDir),
|
|
111
|
+
[
|
|
112
|
+
"export type Id = string;",
|
|
113
|
+
"export interface User { id: Id }",
|
|
114
|
+
"export const user: User = { id: '1' };"
|
|
115
|
+
].join("\n"),
|
|
116
|
+
{ filename: "typechecked.ts", cwd: fixturesDir }
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
test("nest type-checked preset lints TS", async () => {
|
|
121
|
+
await lintText(
|
|
122
|
+
withTsconfigRoot(nestTypeChecked([tsconfigPath]), fixturesDir),
|
|
123
|
+
[
|
|
124
|
+
"export class ExampleService {",
|
|
125
|
+
"\tgetValue(): number {",
|
|
126
|
+
"\t\treturn 1;",
|
|
127
|
+
"\t}",
|
|
128
|
+
"}"
|
|
129
|
+
].join("\n"),
|
|
130
|
+
{ filename: "nest.ts", cwd: fixturesDir }
|
|
131
|
+
);
|
|
132
|
+
});
|