@ololoepepe/eslint-config-typescript 0.0.11 → 0.1.0

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/CHANGELOG.md ADDED
@@ -0,0 +1,67 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file. The format is
4
+ based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this
5
+ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [0.1.0] - 2026-07-01
8
+
9
+ A major modernization of the config, brought to parity with the sibling
10
+ `@ololoepepe/eslint-config` while staying standalone and TypeScript-specific.
11
+ **This release contains breaking changes.**
12
+
13
+ ### Changed
14
+
15
+ - **BREAKING:** Upgraded to **ESLint 10** (`>= 10.4`) and migrated to the **flat
16
+ config** format. The legacy `.eslintrc` format is no longer supported.
17
+ - **BREAKING:** Each entry point now exports a **flat-config array** to be spread
18
+ into a consumer's `eslint.config.js`, instead of a legacy config object
19
+ (`env` / `parser` / `parserOptions` / `plugins: []` / `rules: {}`).
20
+ - **BREAKING:** Replaced `eslint-plugin-import` with **`eslint-plugin-import-x`**
21
+ (all `import/*` rules are now `import-x/*`).
22
+ - **BREAKING:** Core formatting rules were moved to **`@stylistic/eslint-plugin`**
23
+ (`@stylistic/*`), mirroring their removal from ESLint core in v10. Options are
24
+ preserved 1:1.
25
+ - Adopted the **`typescript-eslint@8`** meta-package; typed linting is enabled via
26
+ `parserOptions.projectService`. The `@typescript-eslint/*` rule prefixes are
27
+ unchanged.
28
+ - Bumped **`eslint-plugin-perfectionist`** to `^5.9` — retained as this package's
29
+ distinctive type/interface/enum-sorting feature.
30
+ - Bumped `eslint-plugin-sort-keys-shorthand` to `^5`; it is now the **sole owner**
31
+ of object-literal key ordering (shorthand-first).
32
+
33
+ ### Added
34
+
35
+ - **Layered entry points:**
36
+ - `@ololoepepe/eslint-config-typescript` — env-neutral TypeScript base.
37
+ - `@ololoepepe/eslint-config-typescript/node` — base + Node globals +
38
+ `eslint-plugin-n`.
39
+ - `@ololoepepe/eslint-config-typescript/react` — base + browser globals +
40
+ `@eslint-react`, `eslint-plugin-react-hooks`, and JSX `@stylistic`, scoped to
41
+ `.tsx` / `.jsx`.
42
+ - Correctness plugins on the base: **`unicorn`**, **`regexp`**, **`promise`**, and
43
+ **`@eslint-community/eslint-comments`**, each with an explicitly configured rule
44
+ map.
45
+ - **`typescript`** as a peer dependency (`>=5 <6.1`) and dev dependency.
46
+ - A **fixture-driven test suite** (positive + negative fixtures across the base,
47
+ `/node`, and `/react` layers), alongside the retained self-lint test.
48
+ - The base config now registers TypeScript file extensions (`.ts` / `.cts` /
49
+ `.mts`), so `eslint .` lints TypeScript out of the box.
50
+
51
+ ### Removed
52
+
53
+ - **BREAKING:** Removed `eslint-plugin-import`, `eslint-find-rules`, and the
54
+ `find-rules` script.
55
+ - Removed core rules that no longer exist in ESLint 10, replacing them with their
56
+ modern equivalents or `@typescript-eslint/*` typed analogs (single owner per
57
+ concern, no double-reporting).
58
+
59
+ ### Fixed
60
+
61
+ - Resolved rule conflicts between overlapping plugins:
62
+ - Object-literal key ordering: `perfectionist/sort-objects` disabled in favor of
63
+ `sort-keys-shorthand` (shorthand-first).
64
+ - Import-statement ordering: `perfectionist/sort-imports` disabled in favor of
65
+ `import-x/order` (which carries the project path groups).
66
+ - Disabled `n/no-unsupported-features/es-syntax`, since downlevel syntax for
67
+ TypeScript is owned by the compiler (`tsconfig` `target`).
package/package.json CHANGED
@@ -1,16 +1,20 @@
1
1
  {
2
2
  "name": "@ololoepepe/eslint-config-typescript",
3
- "version": "0.0.11",
3
+ "version": "0.1.0",
4
4
  "description": "ESLint config for TypeScript",
5
5
  "main": "src/index.js",
6
+ "exports": {
7
+ ".": "./src/index.js",
8
+ "./node": "./src/node.js",
9
+ "./react": "./src/react.js"
10
+ },
6
11
  "imports": {
7
12
  "#src/*.js": "./src/*.js"
8
13
  },
9
14
  "type": "module",
10
15
  "scripts": {
11
- "find-rules": "eslint-find-rules --unused ./src/index.js",
12
16
  "lint": "eslint ./src",
13
- "test": "mocha ./test/*"
17
+ "test": "mocha './test/**/*.test.js'"
14
18
  },
15
19
  "publishConfig": {
16
20
  "registry": "https://registry.npmjs.com"
@@ -18,7 +22,8 @@
18
22
  "files": [
19
23
  "src",
20
24
  "package.json",
21
- "README.md"
25
+ "README.md",
26
+ "CHANGELOG.md"
22
27
  ],
23
28
  "repository": {
24
29
  "type": "git",
@@ -31,16 +36,31 @@
31
36
  },
32
37
  "homepage": "https://gitea.void-walkers.com/libs/eslint-config-typescript#README",
33
38
  "dependencies": {
34
- "@typescript-eslint/eslint-plugin": "^8.50.1",
35
- "@typescript-eslint/parser": "^8.50.1",
36
- "eslint": "^8.57.1",
37
- "eslint-import-resolver-typescript": "^4.4.4",
38
- "eslint-plugin-import": "^2.32.0",
39
- "eslint-plugin-perfectionist": "^5.1.0",
40
- "eslint-plugin-sort-keys-shorthand": "^2.3.0"
39
+ "@eslint-community/eslint-plugin-eslint-comments": "^4.7.2",
40
+ "@eslint-react/eslint-plugin": "^5.10.0",
41
+ "@stylistic/eslint-plugin": "^5.0.0",
42
+ "eslint": "^10.6.0",
43
+ "eslint-import-resolver-typescript": "^4.4.0",
44
+ "eslint-plugin-import-x": "^4.17.0",
45
+ "eslint-plugin-n": "^18.2.1",
46
+ "eslint-plugin-perfectionist": "^5.9.0",
47
+ "eslint-plugin-promise": "^7.3.0",
48
+ "eslint-plugin-react-hooks": "^7.1.1",
49
+ "eslint-plugin-regexp": "^3.1.1",
50
+ "eslint-plugin-sort-keys-shorthand": "^5.0.0",
51
+ "eslint-plugin-unicorn": "^69.0.0",
52
+ "globals": "^17.0.0",
53
+ "ts-declaration-location": "^1.0.7",
54
+ "typescript-eslint": "^8.62.0"
41
55
  },
42
56
  "devDependencies": {
43
- "eslint-find-rules": "^5.0.0",
44
- "mocha": "^11.7.5"
57
+ "@types/node": "^22.20.0",
58
+ "@types/react": "^19.2.0",
59
+ "mocha": "^11.7.5",
60
+ "react": "^19.2.0",
61
+ "typescript": "^5.9.0"
62
+ },
63
+ "peerDependencies": {
64
+ "typescript": ">=5 <6.1"
45
65
  }
46
66
  }
package/src/index.js CHANGED
@@ -1,316 +1,88 @@
1
- import pluginImport from '#src/plugins/import.js';
1
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access --
2
+ The ESLint plugins and parser registered in this wiring file are untyped
3
+ third-party modules, so the typed-linting rules treat them as `any`. Suppress
4
+ the unsafe-access reports for the whole file. */
5
+ import eslintComments from '@eslint-community/eslint-plugin-eslint-comments';
6
+ import stylistic from '@stylistic/eslint-plugin';
7
+ import importX from 'eslint-plugin-import-x';
8
+ import perfectionist from 'eslint-plugin-perfectionist';
9
+ import promise from 'eslint-plugin-promise';
10
+ import regexp from 'eslint-plugin-regexp';
11
+ import sortKeysShorthand from 'eslint-plugin-sort-keys-shorthand';
12
+ import unicorn from 'eslint-plugin-unicorn';
13
+ import globals from 'globals';
14
+ import tseslint from 'typescript-eslint';
15
+
16
+ import pluginEslintComments from '#src/plugins/eslint-comments.js';
17
+ import pluginImportX from '#src/plugins/import-x.js';
2
18
  import pluginPerfectionist from '#src/plugins/perfectionist.js';
19
+ import pluginPromise from '#src/plugins/promise.js';
20
+ import pluginRegexp from '#src/plugins/regexp.js';
3
21
  import pluginSortKeysShorthand from '#src/plugins/sort-keys-shorthand.js';
22
+ import pluginStylistic from '#src/plugins/stylistic.js';
4
23
  import pluginTypescript from '#src/plugins/typescript/index.js';
24
+ import pluginUnicorn from '#src/plugins/unicorn.js';
25
+ import rulesCore from '#src/rules/core.js';
5
26
  import rulesNo from '#src/rules/no.js';
6
27
 
7
- export const env = {
8
- es2021: true,
9
- node: true
10
- };
11
-
12
- export const parser = '@typescript-eslint/parser';
13
-
14
- export const parserOptions = {
15
- ecmaFeatures: {
16
- jsx: true
17
- },
18
- ecmaVersion: 'latest',
19
- project: './tsconfig.json',
20
- requireConfigFile: false,
21
- sourceType: 'module'
22
- };
23
-
24
- export const plugins = [
25
- '@typescript-eslint',
26
- 'import',
27
- 'perfectionist',
28
- 'sort-keys-shorthand'
29
- ];
30
-
31
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
32
- export const rules = {
33
- 'accessor-pairs': ['warn', {
34
- enforceForClassMembers: true,
35
- getWithoutSet: false,
36
- setWithoutGet: true
37
- }],
38
- 'array-bracket-newline': ['error', 'consistent'],
39
- 'array-bracket-spacing': ['error', 'never', {
40
- arraysInArrays: false,
41
- objectsInArrays: false,
42
- singleValue: false
43
- }],
44
- 'array-callback-return': ['error', {
45
- allowImplicit: false,
46
- checkForEach: false
47
- }],
48
- 'array-element-newline': ['error', 'consistent'],
49
- 'arrow-body-style': ['error', 'as-needed'],
50
- 'arrow-parens': ['error', 'as-needed', {
51
- requireForBlockBody: false
52
- }],
53
- 'arrow-spacing': ['error', {
54
- after: true,
55
- before: true
56
- }],
57
- 'block-scoped-var': 'error',
58
- 'block-spacing': ['error', 'always'],
59
- 'brace-style': ['error', '1tbs', {
60
- allowSingleLine: false
61
- }],
62
- camelcase: ['error', {
63
- ignoreDestructuring: false,
64
- ignoreGlobals: true,
65
- ignoreImports: false,
66
- properties: 'never'
67
- }],
68
- 'capitalized-comments': ['error', 'always', {
69
- ignoreConsecutiveComments: true,
70
- ignoreInlineComments: false,
71
- ignorePattern: 'webpackChunkName'
72
- }],
73
- 'class-methods-use-this': 'off',
74
- 'comma-dangle': ['error', 'never'],
75
- 'comma-spacing': ['error', {
76
- after: true,
77
- before: false
78
- }],
79
- 'comma-style': ['error', 'last'],
80
- complexity: ['warn', 20],
81
- 'computed-property-spacing': ['error', 'never', {
82
- enforceForClassMembers: true
83
- }],
84
- 'consistent-return': 'off',
85
- 'consistent-this': ['error', 'self'],
86
- 'constructor-super': 'error',
87
- curly: ['error', 'all'],
88
- 'default-case': 'off',
89
- 'default-case-last': 'error',
90
- 'default-param-last': 'error',
91
- 'dot-location': ['error', 'property'],
92
- 'dot-notation': 'off', // NOTE: See TypeScript rule extending this one
93
- 'eol-last': ['error', 'always'],
94
- eqeqeq: ['error', 'always'],
95
- 'for-direction': 'error',
96
- 'func-call-spacing': ['error', 'never'],
97
- 'func-name-matching': ['warn', 'always'],
98
- 'func-names': ['error', 'never', {
99
- generators: 'never'
100
- }],
101
- 'func-style': ['error', 'declaration', {
102
- allowArrowFunctions: true
103
- }],
104
- 'function-call-argument-newline': ['error', 'consistent'],
105
- 'function-paren-newline': ['error', 'multiline-arguments'],
106
- 'generator-star-spacing': ['error', {
107
- after: true,
108
- before: true
109
- }],
110
- 'getter-return': ['error', {
111
- allowImplicit: false
112
- }],
113
- 'grouped-accessor-pairs': ['error', 'getBeforeSet'],
114
- 'guard-for-in': 'error',
115
- 'id-denylist': 'off',
116
- 'id-length': 'off',
117
- 'id-match': 'off',
118
- 'implicit-arrow-linebreak': ['error', 'beside'],
119
- indent: ['error', 2],
120
- 'init-declarations': 'off', // NOTE: See TypeScript rule extending this one
121
- 'jsx-quotes': ['error', 'prefer-double'],
122
- 'key-spacing': ['error', {
123
- afterColon: true,
124
- beforeColon: false
125
- }],
126
- 'keyword-spacing': ['error', {
127
- after: true,
128
- before: true
129
- }],
130
- 'line-comment-position': 'off',
131
- 'linebreak-style': ['error', 'unix'],
132
- 'lines-around-comment': 'off',
133
- 'lines-between-class-members': ['error', 'always', {
134
- exceptAfterSingleLine: true
135
- }],
136
- 'logical-assignment-operators': ['error', 'always', {
137
- enforceForIfStatements: false
138
- }],
139
- 'max-classes-per-file': 'off',
140
- 'max-depth': ['warn', 5],
141
- 'max-len': ['error', {
142
- code: 120,
143
- comments: 120,
144
- ignoreComments: false,
145
- ignoreRegExpLiterals: false,
146
- ignoreStrings: false,
147
- ignoreTemplateLiterals: false,
148
- ignoreTrailingComments: false,
149
- ignoreUrls: false,
150
- tabWidth: 2
151
- }],
152
- 'max-lines': ['warn', {
153
- max: 500,
154
- skipBlankLines: true,
155
- skipComments: true
156
- }],
157
- 'max-lines-per-function': ['warn', {
158
- IIFEs: true,
159
- max: 100,
160
- skipBlankLines: true,
161
- skipComments: true
162
- }],
163
- 'max-nested-callbacks': ['warn', 5],
164
- 'max-params': 'off', // NOTE: See TypeScript rule extending this one
165
- 'max-statements': 'off',
166
- 'max-statements-per-line': ['error', {
167
- max: 1
168
- }],
169
- 'multiline-comment-style': 'off',
170
- 'multiline-ternary': 'off',
171
- 'new-cap': ['error', {
172
- capIsNew: true,
173
- newIsCap: true,
174
- properties: true
175
- }],
176
- 'new-parens': ['error', 'always'],
177
- 'newline-per-chained-call': ['error', {
178
- ignoreChainWithDepth: 3
179
- }],
180
- 'nonblock-statement-body-position': 'off',
181
- 'object-curly-newline': 'off',
182
- 'object-curly-spacing': ['error', 'never', {
183
- arraysInObjects: false,
184
- objectsInObjects: false
185
- }],
186
- 'object-property-newline': 'off', // Reconsider
187
- 'object-shorthand': ['error', 'always', {
188
- avoidExplicitReturnArrows: false,
189
- avoidQuotes: true,
190
- ignoreConstructors: false
191
- }],
192
- 'one-var': ['error', 'never'],
193
- 'one-var-declaration-per-line': 'off',
194
- 'operator-assignment': ['error', 'always'],
195
- 'operator-linebreak': ['error', 'after'],
196
- 'padded-blocks': ['error', 'never', {
197
- allowSingleLineBlocks: false
198
- }],
199
- 'padding-line-between-statements': ['error', {
200
- blankLine: 'always',
201
- next: '*',
202
- prev: 'multiline-block-like'
203
- }],
204
- 'prefer-arrow-callback': ['error', {
205
- allowNamedFunctions: false,
206
- allowUnboundThis: true
207
- }],
208
- 'prefer-const': ['error', {
209
- destructuring: 'all',
210
- ignoreReadBeforeAssign: true
211
- }],
212
- 'prefer-destructuring': 'off', // NOTE: See TypeScript rule extending this one
213
- 'prefer-exponentiation-operator': 'error',
214
- 'prefer-named-capture-group': 'warn',
215
- 'prefer-numeric-literals': 'error',
216
- 'prefer-object-has-own': 'off',
217
- 'prefer-object-spread': 'error',
218
- 'prefer-promise-reject-errors': 'off', // NOTE: See TypeScript rule extending this one
219
- 'prefer-regex-literals': ['error', {
220
- disallowRedundantWrapping: true
221
- }],
222
- 'prefer-rest-params': 'error',
223
- 'prefer-spread': 'error',
224
- 'prefer-template': 'error',
225
- 'quote-props': ['error', 'as-needed', {
226
- keywords: false,
227
- numbers: true,
228
- unnecessary: true
229
- }],
230
- quotes: ['error', 'single', {
231
- allowTemplateLiterals: false,
232
- avoidEscape: true
233
- }],
234
- radix: ['error', 'as-needed'],
235
- 'require-atomic-updates': 'error',
236
- 'require-await': 'off', // NOTE: See TypeScript rule extending this one
237
- 'require-unicode-regexp': 'error',
238
- 'require-yield': 'off',
239
- 'rest-spread-spacing': ['error', 'never'],
240
- semi: ['error', 'always', {
241
- omitLastInOneLineBlock: false
242
- }],
243
- 'semi-spacing': ['error', {
244
- after: true,
245
- before: false
246
- }],
247
- 'semi-style': ['error', 'last'],
248
- 'sort-imports': 'off',
249
- 'sort-keys': 'off',
250
- 'sort-vars': ['error', {
251
- ignoreCase: true
252
- }],
253
- 'space-before-blocks': ['error', 'always'],
254
- 'space-before-function-paren': ['error', {
255
- anonymous: 'always',
256
- asyncArrow: 'always',
257
- named: 'never'
258
- }],
259
- 'space-in-parens': ['error', 'never'],
260
- 'space-infix-ops': ['error', {
261
- int32Hint: false
262
- }],
263
- 'space-unary-ops': ['error', {
264
- nonwords: false,
265
- words: true
266
- }],
267
- 'spaced-comment': ['error', 'always', {
268
- block: {
269
- balanced: true,
270
- exceptions: ['-', '+', '*'],
271
- markers: ['!', '*']
28
+ export default [{
29
+ files: [
30
+ '**/*.ts',
31
+ '**/*.tsx',
32
+ '**/*.cts',
33
+ '**/*.mts',
34
+ '**/*.js',
35
+ '**/*.jsx',
36
+ '**/*.cjs',
37
+ '**/*.mjs'
38
+ ],
39
+ languageOptions: {
40
+ ecmaVersion: 'latest',
41
+ globals: {
42
+ ...globals.es2021
272
43
  },
273
- line: {
274
- exceptions: ['-', '+', '*'],
275
- markers: ['!', '/', '=>']
276
- }
277
- }],
278
- strict: ['error', 'never'],
279
- 'switch-colon-spacing': ['error', {
280
- after: true,
281
- before: false
282
- }],
283
- 'symbol-description': 'error',
284
- 'template-curly-spacing': ['error', 'never'],
285
- 'template-tag-spacing': ['error', 'never'],
286
- 'unicode-bom': ['error', 'never'],
287
- 'use-isnan': ['error', {
288
- enforceForIndexOf: true,
289
- enforceForSwitchCase: true
290
- }],
291
- 'valid-typeof': ['error', {
292
- requireStringLiterals: false
293
- }],
294
- 'vars-on-top': 'error',
295
- 'wrap-iife': ['error', 'inside', {
296
- functionPrototypeMethods: true
297
- }],
298
- 'wrap-regex': 'off',
299
- 'yield-star-spacing': ['error', 'both'],
300
- yoda: ['error', 'never'],
301
- ...rulesNo,
302
- /* eslint-disable @typescript-eslint/no-unsafe-member-access */
303
- ...pluginTypescript.rules,
304
- ...pluginPerfectionist.rules,
305
- ...pluginImport.rules,
306
- ...pluginSortKeysShorthand.rules
307
- /* eslint-enable @typescript-eslint/no-unsafe-member-access */
308
- };
309
-
310
- export const settings = {
311
- 'import/resolver': {
312
- typescript: {
313
- project: './tsconfig.json'
44
+ parser: tseslint.parser,
45
+ parserOptions: {
46
+ ecmaFeatures: {
47
+ jsx: true
48
+ },
49
+ projectService: true
50
+ },
51
+ sourceType: 'module'
52
+ },
53
+ linterOptions: {
54
+ reportUnusedDisableDirectives: 'error'
55
+ },
56
+ name: '@ololoepepe/eslint-config-typescript',
57
+ plugins: {
58
+ perfectionist,
59
+ promise,
60
+ regexp,
61
+ unicorn,
62
+ '@eslint-community/eslint-comments': eslintComments,
63
+ '@stylistic': stylistic,
64
+ '@typescript-eslint': tseslint.plugin,
65
+ 'import-x': importX,
66
+ 'sort-keys-shorthand': sortKeysShorthand
67
+ },
68
+ rules: {
69
+ ...rulesCore,
70
+ ...rulesNo,
71
+ ...pluginEslintComments.rules,
72
+ ...pluginStylistic.rules,
73
+ ...pluginTypescript.rules,
74
+ ...pluginImportX.rules,
75
+ ...pluginPerfectionist.rules,
76
+ ...pluginPromise.rules,
77
+ ...pluginRegexp.rules,
78
+ ...pluginSortKeysShorthand.rules,
79
+ ...pluginUnicorn.rules
80
+ },
81
+ settings: {
82
+ 'import-x/resolver': {
83
+ typescript: {
84
+ project: './tsconfig.json'
85
+ }
314
86
  }
315
87
  }
316
- };
88
+ }];
package/src/node.js ADDED
@@ -0,0 +1,27 @@
1
+ /* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access --
2
+ The ESLint plugin and globals registered in this wiring file are untyped
3
+ third-party modules, so the typed-linting rules treat them as `any`. Suppress
4
+ the unsafe-access reports for the whole file. */
5
+ import n from 'eslint-plugin-n';
6
+ import globals from 'globals';
7
+
8
+ import base from '#src/index.js';
9
+ import pluginN from '#src/plugins/n.js';
10
+
11
+ export default [
12
+ ...base,
13
+ {
14
+ languageOptions: {
15
+ globals: {
16
+ ...globals.node
17
+ }
18
+ },
19
+ name: '@ololoepepe/eslint-config-typescript/node',
20
+ plugins: {
21
+ n
22
+ },
23
+ rules: {
24
+ ...pluginN.rules
25
+ }
26
+ }
27
+ ];
@@ -0,0 +1,16 @@
1
+ export default {
2
+ rules: {
3
+ '@eslint-community/eslint-comments/disable-enable-pair': ['error', {
4
+ allowWholeFile: true
5
+ }],
6
+ '@eslint-community/eslint-comments/no-aggregating-enable': 'error',
7
+ '@eslint-community/eslint-comments/no-duplicate-disable': 'error',
8
+ '@eslint-community/eslint-comments/no-restricted-disable': 'off',
9
+ '@eslint-community/eslint-comments/no-unlimited-disable': 'error',
10
+ // NOTE: `no-unused-disable` is deprecated; `linterOptions.reportUnusedDisableDirectives`
11
+ // (set to 'error' in src/index.js) is the owner for unused disable directives.
12
+ '@eslint-community/eslint-comments/no-unused-enable': 'error',
13
+ '@eslint-community/eslint-comments/no-use': 'off',
14
+ '@eslint-community/eslint-comments/require-description': 'error'
15
+ }
16
+ };