@tuomashatakka/eslint-config 2.2.2 → 2.3.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/eslint.config.mjs CHANGED
@@ -1,58 +1,4 @@
1
- /* eslint-disable multiline-comment-style */
2
- import stylistic from '@stylistic/eslint-plugin'
3
- import tsplugin from '@typescript-eslint/eslint-plugin'
4
- import importPlugin from 'eslint-plugin-import'
5
- import react from 'eslint-plugin-react'
6
- import globals from 'globals'
7
- import tseslint from 'typescript-eslint'
1
+ import { config } from './index.mjs'
8
2
 
9
- import rules from './rules.mjs'
10
3
 
11
-
12
- const plugins = {
13
- 'react': react,
14
- 'import': importPlugin,
15
- '@stylistic': stylistic,
16
- '@typescript-eslint': tsplugin,
17
- }
18
-
19
- /**
20
- * @type {tseslint.configs.base}
21
- **/
22
- const config = tseslint.config(
23
- ...tseslint.configs.recommended,
24
- {
25
- languageOptions: {
26
- parserOptions: {
27
- ecmaFeatures: {
28
- jsx: true,
29
- },
30
- },
31
- globals: {
32
- ...globals.browser,
33
- ...globals.node,
34
- }
35
- },
36
- settings: {
37
- 'import/internal-regex': '^@/(.+)',
38
- 'import/resolver': {
39
- node: {
40
- extensions: [ '.js', '.jsx', '.ts', '.tsx', '.mjs', '.cjs' ],
41
- },
42
- },
43
- 'react': {
44
- version: 'detect',
45
- },
46
- },
47
- plugins,
48
- rules,
49
- }
50
- )
51
-
52
- /**
53
- * @summary ESLint configuration
54
- * @description Opinionated yet functional AF base config for ESLint
55
- * @author {@author}
56
- * @version {@version}
57
- **/
58
4
  export default config
package/index.mjs CHANGED
@@ -1,34 +1,58 @@
1
+ import stylistic from '@stylistic/eslint-plugin'
2
+ import tsplugin from '@typescript-eslint/eslint-plugin'
3
+ import importPlugin from 'eslint-plugin-import'
4
+ import noInlineMultilineTypesPlugin from 'eslint-plugin-no-inline-multiline-types'
5
+ import whitespacedPlugin from 'eslint-plugin-whitespaced'
6
+ import omitPlugin from 'eslint-plugin-omit-unnecessary'
7
+ import react from 'eslint-plugin-react'
8
+ import tailwindCssPlugin from 'eslint-plugin-tailwindcss'
1
9
  import globals from 'globals'
2
10
  import tseslint from 'typescript-eslint'
3
11
 
4
- import config from './eslint.config.mjs'
12
+ import { rules } from './rules.mjs'
5
13
 
6
14
 
7
- const configType = tseslint.configs.base
15
+ const plugins = {
16
+ 'react': react,
17
+ 'import': importPlugin,
18
+ '@stylistic': stylistic,
19
+ '@typescript-eslint': tsplugin,
20
+ 'tailwindcss': tailwindCssPlugin,
21
+ 'omit': omitPlugin,
22
+ 'no-inline-types': noInlineMultilineTypesPlugin,
23
+ 'whitespaced': whitespacedPlugin,
24
+ }
25
+
26
+ export { rules }
27
+
28
+ export const baseConfig = {
29
+ files: [ '**/*.{js,jsx,mjs,cjs,ts,tsx}' ],
30
+ languageOptions: {
31
+ sourceType: 'module',
32
+ ecmaVersion: 'latest',
33
+ parserOptions: { ecmaFeatures: { jsx: true }},
34
+ globals: { ...globals.browser, ...globals.node },
35
+ },
36
+ settings: {
37
+ 'react': { version: 'detect' },
38
+ 'import/internal-regex': '^@/(.+)',
39
+ },
40
+ ignores: [ '**/node_modules/**' ],
41
+ plugins,
42
+ rules,
43
+ }
44
+
8
45
 
9
46
  /**
10
- * @name config
11
- * @type {typeof configType}
47
+ * @type {tseslint.configs.base}
12
48
  */
13
- export default [
14
- ...config,
15
- {
16
- files: [ '**/*.{js,jsx,mjs,cjs,ts,tsx}' ],
17
- languageOptions: {
18
- ecmaVersion: 'latest',
19
- sourceType: 'module',
20
- parserOptions: {
21
- ecmaFeatures: {
22
- jsx: true,
23
- },
24
- },
25
- globals: {
26
- ...globals.browser,
27
- },
28
- }
29
- }]
30
-
31
- export {
32
- config,
33
- configType
34
- }
49
+ export const config = tseslint.config(
50
+ ...tseslint.configs.recommended,
51
+ baseConfig)
52
+
53
+
54
+ /**
55
+ * @summary ESLint configuration
56
+ * @description Opinionated yet functional AF base config for ESLint
57
+ */
58
+ export default config
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@tuomashatakka/eslint-config",
3
- "version": "2.2.2",
3
+ "version": "2.3.0",
4
4
  "description": "Default eslint configuration",
5
5
  "type": "module",
6
6
  "main": "index.mjs",
7
7
  "scripts": {
8
- "lint": "eslint . --config eslint.config.mjs"
8
+ "lint": "eslint . --config index.mjs"
9
9
  },
10
10
  "repository": {
11
11
  "type": "git",
@@ -19,23 +19,36 @@
19
19
  },
20
20
  "homepage": "https://github.com/tuomashatakka/eslint-config#readme",
21
21
  "peerDependencies": {
22
- "@eslint/js": ">=9.13.0",
22
+ "eslint": ">=9.13.0",
23
23
  "react": "*",
24
- "@stylistic/eslint-plugin": "*",
25
- "typescript-eslint": ">=8.1.0"
24
+ "typescript": "*"
25
+ },
26
+ "dependencies": {
27
+ "eslint": "^9.13.0",
28
+ "@stylistic/eslint-plugin": "^2.9.0",
29
+ "typescript-eslint": "^8.11.0",
30
+ "globals": "^15.11.0",
31
+ "typescript": "^5.6.3",
32
+ "eslint-plugin-react": "*",
33
+ "eslint-plugin-react-hooks": "*",
34
+ "eslint-plugin-import": "*",
35
+ "eslint-plugin-tailwindcss": "*",
36
+ "eslint-plugin-next": "*",
37
+ "@typescript-eslint/eslint-plugin": "*",
38
+ "eslint-plugin-no-inline-multiline-types": "*",
39
+ "eslint-plugin-omit-unnecessary": "*",
40
+ "eslint-plugin-whitespaced": "*"
26
41
  },
27
42
  "devDependencies": {
28
43
  "@eslint/compat": "^1.2.1",
29
44
  "@eslint/eslintrc": "^3.1.0",
30
45
  "@eslint/js": "^9.13.0",
31
- "@eslint/config-array": "^1.5.3",
32
46
  "@stylistic/eslint-plugin": "^2.9.0",
33
47
  "@stylistic/eslint-plugin-ts": "^2.9.0",
34
48
  "@types/eslint__eslintrc": "^2.1.2",
35
49
  "@types/eslint__js": "^8.42.3",
36
50
  "@typescript-eslint/eslint-plugin": "^8.11.0",
37
51
  "@typescript-eslint/parser": "^8.11.0",
38
- "eslint": "^9.13.0",
39
52
  "eslint-plugin-block-padding": "^0.0.3",
40
53
  "eslint-plugin-import": "^2.31.0",
41
54
  "eslint-plugin-react": "^7.37.2",
package/rules.mjs CHANGED
@@ -2,7 +2,6 @@
2
2
  * @exports {import("eslint/rules").ESLintRules} rules
3
3
  * @type {import("@eslint/core").RulesConfig}
4
4
  */
5
-
6
5
  export const rules = {
7
6
 
8
7
  // '@next/next/no-styled-jsx-in-document': [ 'error' ],
@@ -190,7 +189,295 @@ export const rules = {
190
189
  '@stylistic/jsx-curly-spacing': [ 'warn', { spacing: { objectLiterals: 'always' }}],
191
190
  '@stylistic/implicit-arrow-linebreak': [ 0 ],
192
191
  '@stylistic/arrow-parens': [ 1, 'as-needed', { requireForBlockBody: true }],
193
- '@stylistic/space-before-function-paren': [ 1, 'always' ]
192
+ '@stylistic/space-before-function-paren': [ 1, 'always' ],
193
+
194
+ 'tailwindcss/no-custom-classname': 'off',
195
+ 'tailwindcss/classnames-order': 'off',
196
+
197
+ 'no-inline-types/no-inline-multiline-types': 'warn',
198
+
199
+ 'multiline-comment-style': [
200
+ 'warn',
201
+ 'separate-lines',
202
+ { checkJSDoc: false },
203
+ ],
204
+ '@stylistic/lines-around-comment': [
205
+ 'warn',
206
+ {
207
+ beforeBlockComment: true,
208
+ beforeLineComment: false,
209
+ afterLineComment: false,
210
+ allowClassEnd: true,
211
+ allowBlockEnd: true,
212
+ },
213
+ ],
214
+
215
+ // TODO
216
+ 'import/no-extraneous-dependencies': [ 'warn' ],
217
+ 'import/consistent-type-specifier-style': [ 'warn', 'prefer-top-level' ],
218
+ 'import/newline-after-import': [ 'warn', { count: 2 }],
219
+ 'import/no-unassigned-import': [
220
+ 'error',
221
+ { allow: [ '**/*.{le,c,sc,sa}ss', 'server-only' ]},
222
+ ],
223
+ 'import/prefer-default-export': [ 'off' ],
224
+ 'import/no-mutable-exports': [ 'error' ],
225
+ 'import/order': [
226
+ 'off',
227
+ {
228
+ 'groups': [
229
+ 'builtin',
230
+ 'type',
231
+ 'external',
232
+ [ 'parent', 'sibling', 'index' ],
233
+ [ 'internal', 'object' ],
234
+ ],
235
+ 'alphabetize': { order: 'asc', caseInsensitive: false },
236
+ 'distinctGroup': true,
237
+ 'warnOnUnassignedImports': true,
238
+ 'newlines-between': 'always',
239
+ 'pathGroups': [{ group: 'internal', pattern: '**/*.s?css' }],
240
+ },
241
+ ],
242
+
243
+ // Typescript
244
+ '@stylistic/ban-ts-comment': [ 'off', 'allow-single-line' ],
245
+
246
+ // Enforced practices (enforce functional and orthogonal code)
247
+ 'complexity': [ 'warn', { max: 14 }],
248
+ 'eqeqeq': [ 'warn', 'smart' ],
249
+ 'arrow-body-style': [ 'warn', 'as-needed' ],
250
+ 'max-lines': [
251
+ 'warn',
252
+ { max: 666, skipComments: true, skipBlankLines: true },
253
+ ],
254
+ 'max-statements': [ 'warn', 40 ],
255
+ 'max-depth': [ 'warn', 6 ],
256
+ 'no-console': [ 0 ],
257
+ 'no-debugger': [ 'warn' ],
258
+ 'dot-notation': [ 'warn' ],
259
+ 'no-undef': [ 0 ],
260
+ 'use-isnan': [ 'error' ],
261
+ 'no-obj-calls': [ 'error' ],
262
+ 'no-new-symbol': [ 'error' ],
263
+ 'no-func-assign': [ 'error' ],
264
+ 'no-class-assign': [ 'error' ],
265
+ 'no-array-constructor': [ 'error' ],
266
+
267
+ 'omit/omit-unnecessary-parens-brackets': [ 'warn' ],
268
+
269
+ // Stylistic formatting opinionations
270
+ // '@stylistic/function-paren-newline': [ 'warn', 'always' ],
271
+ '@stylistic/function-call-spacing': [ 'warn', 'never' ],
272
+ '@stylistic/computed-property-spacing': [ 'warn', 'never' ],
273
+ '@stylistic/brace-style': [ 'warn', 'stroustrup', { allowSingleLine: false }],
274
+ '@stylistic/comma-dangle': [ 'warn', 'only-multiline' ],
275
+ '@stylistic/comma-spacing': [ 'warn', { before: false, after: true }],
276
+ '@stylistic/comma-style': [ 'warn', 'last' ],
277
+ '@stylistic/key-spacing': [
278
+ 'warn',
279
+ { beforeColon: false, afterColon: true, align: 'value' },
280
+ ],
281
+ '@stylistic/keyword-spacing': [ 'warn', { before: true, after: true }],
282
+ '@stylistic/object-property-newline': [
283
+ 'warn',
284
+ {
285
+ allowAllPropertiesOnSameLine: true,
286
+ },
287
+ ],
288
+ '@stylistic/max-len': [ 0, 400 ],
289
+ '@stylistic/no-tabs': [ 'warn' ],
290
+ '@stylistic/no-extra-parens': [ 'warn', 'all' ],
291
+ '@stylistic/jsx-function-call-newline': [ 'warn', 'always' ],
292
+ '@stylistic/no-multiple-empty-lines': [
293
+ 'warn',
294
+ { max: 2, maxEOF: 0, maxBOF: 0 },
295
+ ],
296
+ '@stylistic/no-trailing-spaces': [
297
+ 'warn',
298
+ { skipBlankLines: false, ignoreComments: false },
299
+ ],
300
+ '@stylistic/no-confusing-arrow': [ 0 ],
301
+ '@stylistic/no-whitespace-before-property': [ 'warn' ],
302
+ '@stylistic/space-in-parens': [ 'warn', 'never' ],
303
+ '@stylistic/space-infix-ops': [ 'warn', { int32Hint: false }],
304
+ '@stylistic/space-unary-ops': [ 'warn', { words: true, nonwords: false }],
305
+ '@stylistic/switch-colon-spacing': [ 'warn', { after: true, before: false }],
306
+ '@stylistic/template-curly-spacing': [ 'warn', 'never' ],
307
+ '@stylistic/wrap-iife': [ 'warn', 'inside' ],
308
+ '@stylistic/wrap-regex': [ 'warn' ],
309
+ '@stylistic/object-curly-spacing': [
310
+ 'warn',
311
+ 'always',
312
+ { arraysInObjects: false, objectsInObjects: false },
313
+ ],
314
+ '@stylistic/array-bracket-spacing': [
315
+ 'warn',
316
+ 'always',
317
+ { arraysInArrays: false, objectsInArrays: false },
318
+ ],
319
+ '@stylistic/new-parens': [ 'warn', 'always' ],
320
+ '@stylistic/operator-linebreak': [
321
+ 'warn',
322
+ 'after',
323
+ { overrides: { '?': 'before', ':': 'before' }},
324
+ ],
325
+ '@stylistic/quote-props': [
326
+ 'warn',
327
+ 'consistent-as-needed',
328
+ { keywords: false, unnecessary: true, numbers: false },
329
+ ],
330
+ '@stylistic/indent': [
331
+ 'warn',
332
+ 2,
333
+ { SwitchCase: 1, CallExpression: { arguments: 'first' }},
334
+ ],
335
+ '@stylistic/arrow-spacing': [ 'warn' ],
336
+ '@stylistic/newline-per-chained-call': [
337
+ 'warn',
338
+ { ignoreChainWithDepth: 2 },
339
+ ],
340
+ '@stylistic/lines-between-class-members': [
341
+ 'warn',
342
+ 'always',
343
+ { exceptAfterSingleLine: true },
344
+ ],
345
+ '@stylistic/one-var-declaration-per-line': [ 'warn', 'always' ],
346
+
347
+ // @stylistic
348
+ '@stylistic/arrow-parens': [ 'warn', 'as-needed' ],
349
+ '@stylistic/dot-location': [ 'warn', 'property' ],
350
+ '@stylistic/eol-last': [ 'warn', 'always' ],
351
+ '@stylistic/multiline-ternary': [ 'warn', 'always-multiline' ],
352
+ '@stylistic/no-floating-decimal': [ 'warn' ],
353
+ '@stylistic/no-extra-semi': [ 'warn' ],
354
+ '@stylistic/semi-spacing': [ 'warn', { before: false, after: true }],
355
+ '@stylistic/semi-style': [ 'warn', 'last' ],
356
+ '@stylistic/semi': [ 'warn', 'never' ],
357
+ '@stylistic/space-before-function-paren': [
358
+ 'warn',
359
+ { anonymous: 'always', named: 'always', asyncArrow: 'always' },
360
+ ],
361
+ '@stylistic/template-tag-spacing': [ 'warn', 'always' ],
362
+ '@stylistic/yield-star-spacing': [ 'warn', 'after' ],
363
+ '@stylistic/quotes': [
364
+ 'warn',
365
+ 'single',
366
+ { avoidEscape: true, allowTemplateLiterals: true },
367
+ ],
368
+
369
+ // JSX/React
370
+ '@stylistic/jsx-quotes': [ 'warn', 'prefer-single' ],
371
+ '@stylistic/jsx-newline': [
372
+ 'warn',
373
+ { prevent: true, allowMultilines: true },
374
+ ],
375
+ '@stylistic/jsx-props-no-multi-spaces': [ 'warn' ],
376
+ '@stylistic/jsx-equals-spacing': [ 'warn', 'never' ],
377
+ '@stylistic/jsx-max-props-per-line': [ 'warn', { maximum: 1, when: 'multiline' }],
378
+ '@stylistic/jsx-self-closing-comp': [ 'warn', { component: true, html: true }],
379
+ '@stylistic/jsx-tag-spacing': [
380
+ 'warn',
381
+ {
382
+ closingSlash: 'never',
383
+ beforeSelfClosing: 'always',
384
+ beforeClosing: 'never',
385
+ afterOpening: 'never',
386
+ },
387
+ ],
388
+ 'react/no-unescaped-entities': [ 'error', { forbid: [ '>', '}' ]}],
389
+ 'react/jsx-uses-vars': [ 'error' ],
390
+ 'react/jsx-uses-react': [ 'error' ],
391
+ 'react/style-prop-object': [ 'error', { allow: []}],
392
+ 'react/prefer-stateless-function': [
393
+ 'error',
394
+ { ignorePureComponents: false },
395
+ ],
396
+ 'react/no-invalid-html-attribute': [ 'error', []],
397
+ 'react/hook-use-state': [ 'warn', { allowDestructuredState: true }],
398
+ 'react/jsx-no-useless-fragment': [ 'warn', { allowExpressions: true }],
399
+ 'react/jsx-no-target-blank': [ 'warn', { enforceDynamicLinks: 'always' }],
400
+ 'react/jsx-closing-bracket-location': [ 'warn', 'after-props' ],
401
+ 'react/jsx-closing-tag-location': [ 'warn', 'line-aligned' ],
402
+ 'react/jsx-equals-spacing': [ 'warn', 'never' ],
403
+ 'react/jsx-first-prop-new-line': [ 'warn', 'multiline' ],
404
+ 'react/jsx-max-props-per-line': [ 'warn', { maximum: 1, when: 'multiline' }],
405
+ 'react/jsx-no-constructed-context-values': [ 'warn' ],
406
+ 'react/jsx-no-script-url': [ 'warn' ],
407
+ 'react/jsx-no-comment-textnodes': [ 'warn' ],
408
+ 'react/jsx-no-duplicate-props': [ 'warn' ],
409
+ 'react/jsx-no-undef': [ 'warn' ],
410
+ 'react/jsx-pascal-case': [ 'warn' ],
411
+ 'react/jsx-curly-brace-presence': [
412
+ 'warn',
413
+ { props: 'never', children: 'never' },
414
+ ],
415
+ 'react/jsx-curly-spacing': [ 'warn', { when: 'always', spacing: { objectLiterals: 'never' }}],
416
+ 'react/display-name': [ 'warn', { checkContextObjects: true }],
417
+
418
+ 'react-hooks/exhaustive-deps': 0,
419
+
420
+ '@stylistic/jsx-indent-props': [
421
+ 'warn',
422
+ { indentMode: 2, ignoreTernaryOperator: true },
423
+ ],
424
+
425
+ // Block padding
426
+ '@stylistic/no-multi-spaces': [
427
+ 'warn',
428
+ {
429
+ exceptions: {
430
+ Property: true,
431
+ TSTypeAnnotation: true,
432
+ VariableDeclarator: true,
433
+ ObjectExpression: false,
434
+ },
435
+ },
436
+ ],
437
+ '@stylistic/spaced-comment': [ 'warn', 'always', { markers: [ '/' ]}],
438
+ '@stylistic/padded-blocks': [ 'warn', 'never' ],
439
+ '@stylistic/nonblock-statement-body-position': [ 'warn', 'below' ],
440
+ '@stylistic/space-before-blocks': [ 'warn', 'always' ],
441
+
442
+ '@typescript-eslint/no-implicit-any': 0,
443
+
444
+ 'no-unused-vars': 0,
445
+ '@typescript-eslint/no-unused-vars': 0,
446
+
447
+ '@stylistic/padding-line-between-statements': [
448
+ 'warn',
449
+ { blankLine: 'always', prev: 'directive', next: '*' },
450
+ { blankLine: 'any', prev: 'directive', next: 'directive' },
451
+
452
+ { blankLine: 'always', next: [ 'const', 'let', 'var' ], prev: '*' },
453
+ { blankLine: 'any', prev: [ 'const', 'let', 'var' ], next: '*' },
454
+ {
455
+ blankLine: 'any',
456
+ prev: [ 'const', 'let', 'var' ],
457
+ next: [ 'const', 'let', 'var' ],
458
+ },
459
+
460
+ { prev: 'import', next: '*', blankLine: 'always' },
461
+ { prev: 'import', next: 'import', blankLine: 'any' },
462
+
463
+ { blankLine: 'always', prev: '*', next: [ 'export' ]},
464
+ { blankLine: 'any', prev: 'export', next: [ 'export' ]},
465
+
466
+ { blankLine: 'never', prev: 'case', next: '*' },
467
+ { blankLine: 'never', prev: 'default', next: '*' },
468
+
469
+ {
470
+ blankLine: 'always',
471
+ prev: [ 'block-like', 'block' ],
472
+ next: [ 'multiline-expression', 'function', 'block-like', 'block' ],
473
+ },
474
+ {
475
+ blankLine: 'any',
476
+ prev: [ 'multiline-expression', 'function', 'block-like', 'block' ],
477
+ next: [ 'multiline-expression', 'function', 'block-like', 'block' ],
478
+ },
479
+ ],
194
480
  }
195
481
 
482
+ // Make sure we export both named and default exports
196
483
  export default rules