@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.
@@ -1,22 +1,48 @@
1
- name: ci
1
+ name: CI
2
2
 
3
3
  on:
4
- pull_request:
5
- branches: [develop, maestro]
6
4
  push:
7
- branches: [develop, maestro]
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
- - uses: actions/checkout@v4
17
- - uses: actions/setup-node@v4
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: 20
34
+ node-version: ${{ matrix.node-version }}
20
35
  cache: npm
21
- - run: npm ci --ignore-scripts --prefer-offline
22
- - run: npm run lint:ci
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: [maestro]
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 --ignore-scripts --prefer-offline
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 ci --ignore-scripts --prefer-offline
40
+ - run: npm i -g npm@^11.5.1
41
41
 
42
- - name: Configure npm auth (userconfig)
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
- NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
61
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
51
+ NPM_CONFIG_PROVENANCE: true
package/CHANGELOG.md CHANGED
@@ -1,10 +1,17 @@
1
1
  # @eslint-umbrella/presets
2
2
 
3
+ ## 1.1.3
4
+
5
+ ### Patch Changes
6
+
7
+ - some fixes
8
+
3
9
  ## 1.1.2
4
10
 
5
11
  ### Patch Changes
6
12
 
7
- - 22a0301: something
13
+ - e43ff12: something
14
+ - dwd
8
15
 
9
16
  ## 1.1.1
10
17
 
package/package.json CHANGED
@@ -1,11 +1,21 @@
1
1
  {
2
2
  "name": "@eslint-umbrella/presets",
3
- "version": "1.1.2",
3
+ "version": "1.1.3",
4
4
  "type": "module",
5
- "description": "Pinned ESLint flat config presets for React, Next.js, Express, NestJS, React Native, React-PDF, and base/test",
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-import": "2.31.0",
33
- "eslint-plugin-react": "7.37.1",
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
- "@stylistic/eslint-plugin": "^5.3.1",
43
- "@eslint/js": "^9.35.0",
44
- "eslint-plugin-react-native": "^5.0.0"
45
- },
46
- "devDependencies": {
47
- "@changesets/cli": "^2.29.7",
48
- "eslint": "^9.35.0",
49
- "nodemon": "^3.1.10"
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
@@ -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,5 @@
1
+ export class ExampleService {
2
+ getValue(): number {
3
+ return 1;
4
+ }
5
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "ESNext",
5
+ "moduleResolution": "Bundler",
6
+ "strict": true,
7
+ "noEmit": true
8
+ },
9
+ "include": ["**/*.ts", "**/*.tsx"]
10
+ }
@@ -0,0 +1,6 @@
1
+ export const value = 1;
2
+
3
+ export async function getValue(): Promise<number> {
4
+ await Promise.resolve();
5
+ return value;
6
+ }
@@ -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
+ });