@vortiquo/eslint-config 1.2.3 → 2.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vortiquo/eslint-config",
3
- "version": "1.2.3",
3
+ "version": "2.1.0",
4
4
  "description": "Modern ESLint v9 flat configurations with TypeScript, React, Next.js, and Node.js support",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -11,12 +11,13 @@
11
11
  "url": "https://github.com/vortiquo/node-eslint-config"
12
12
  },
13
13
  "scripts": {
14
- "lint": "ls-lint",
14
+ "lint": "eslint --max-warnings 0",
15
15
  "format": "prettier --write .",
16
16
  "format:check": "prettier --check .",
17
- "test": "node scripts/validate-configs.js && node tests/test-configs.js",
18
- "test:configs": "node tests/test-configs.js",
19
- "prepack": "npm run test",
17
+ "test:imports": "node ./tests/smoke-imports.mjs",
18
+ "test:fixtures": "node ./tests/run-eslint-fixtures.mjs",
19
+ "test": "pnpm run test:imports && pnpm run test:fixtures",
20
+ "prepack": "pnpm run test",
20
21
  "commit": "cz",
21
22
  "prepare": "husky"
22
23
  },
@@ -41,30 +42,25 @@
41
42
  "shared-config"
42
43
  ],
43
44
  "exports": {
44
- ".": "./index.js",
45
- "./base": "./base.js",
46
- "./base-typescript": "./base-typescript.js",
47
- "./react": "./react.js",
48
- "./react-library": "./react-library.js",
49
- "./react-library-js": "./react-library-js.js",
50
- "./nextjs": "./nextjs.js",
51
- "./server": "./server.js",
52
- "./nestjs": "./nestjs.js",
53
- "./node-library": "./node-library.js",
54
- "./node-library-js": "./node-library-js.js"
45
+ ".": "./src/index.js",
46
+ "./base": "./src/base/index.js",
47
+ "./ts": "./src/ts/index.js",
48
+ "./ts/strict": "./src/ts/strict.js",
49
+ "./server": "./src/server/index.js",
50
+ "./server/strict": "./src/server/strict.js",
51
+ "./node-lib": "./src/node-lib/index.js",
52
+ "./node-lib/strict": "./src/node-lib/strict.js",
53
+ "./node-lib/js": "./src/node-lib/js.js",
54
+ "./node-lib/js-strict": "./src/node-lib/js-strict.js",
55
+ "./react": "./src/react/index.js",
56
+ "./react/strict": "./src/react/strict.js",
57
+ "./react-lib": "./src/react-lib/index.js",
58
+ "./react-lib/strict": "./src/react-lib/strict.js",
59
+ "./next": "./src/next/index.js",
60
+ "./next/strict": "./src/next/strict.js"
55
61
  },
56
62
  "files": [
57
- "index.js",
58
- "base.js",
59
- "base-typescript.js",
60
- "react.js",
61
- "react-library.js",
62
- "react-library-js.js",
63
- "nextjs.js",
64
- "server.js",
65
- "nestjs.js",
66
- "node-library.js",
67
- "node-library-js.js",
63
+ "src/**/*.js",
68
64
  "README.md",
69
65
  "LICENSE"
70
66
  ],
@@ -72,9 +68,7 @@
72
68
  "@eslint/js": "^9.17.0",
73
69
  "@next/eslint-plugin-next": "^16.1.0",
74
70
  "eslint-config-prettier": "^10.0.1",
75
- "eslint-import-resolver-typescript": "^4.4.4",
76
71
  "eslint-plugin-import": "^2.31.0",
77
- "eslint-plugin-only-warn": "^1.1.0",
78
72
  "eslint-plugin-react": "^7.37.2",
79
73
  "eslint-plugin-react-hooks": "^7.0.1",
80
74
  "eslint-plugin-simple-import-sort": "^12.1.1",
@@ -87,6 +81,7 @@
87
81
  "@commitlint/config-conventional": "^20.2.0",
88
82
  "@ls-lint/ls-lint": "^2.3.1",
89
83
  "cz-conventional-changelog": "^3.3.0",
84
+ "eslint": "^9.39.2",
90
85
  "husky": "^9.1.7",
91
86
  "lint-staged": "^16.2.7",
92
87
  "prettier": "^3.7.4"
@@ -1,7 +1,6 @@
1
1
  import js from '@eslint/js';
2
2
  import eslintConfigPrettier from 'eslint-config-prettier';
3
3
  import importPlugin from 'eslint-plugin-import';
4
- import onlyWarn from 'eslint-plugin-only-warn';
5
4
  import simpleImportSort from 'eslint-plugin-simple-import-sort';
6
5
  import turboPlugin from 'eslint-plugin-turbo';
7
6
 
@@ -12,15 +11,27 @@ import turboPlugin from 'eslint-plugin-turbo';
12
11
  * @type {import("eslint").Linter.Config[]}
13
12
  */
14
13
  export const base = [
14
+ {
15
+ name: '@vortiquo/base:ignores',
16
+ ignores: [
17
+ '**/node_modules/**',
18
+ '**/dist/**',
19
+ '**/build/**',
20
+ '**/.next/**',
21
+ '**/coverage/**',
22
+ '**/.turbo/**',
23
+ '**/public/**',
24
+ ],
25
+ },
26
+
15
27
  js.configs.recommended,
16
- eslintConfigPrettier,
28
+
17
29
  {
18
- name: 'vortiquo/base',
30
+ name: '@vortiquo/base:plugins',
19
31
  plugins: {
20
32
  turbo: turboPlugin,
21
33
  import: importPlugin,
22
34
  'simple-import-sort': simpleImportSort,
23
- onlyWarn,
24
35
  },
25
36
  rules: {
26
37
  // Turbo
@@ -58,20 +69,7 @@ export const base = [
58
69
  },
59
70
  },
60
71
  {
61
- name: 'vortiquo/base/ignores',
62
- ignores: [
63
- '**/node_modules/**',
64
- '**/dist/**',
65
- '**/build/**',
66
- '**/.next/**',
67
- '**/coverage/**',
68
- '**/.turbo/**',
69
- '**/public/**',
70
- ],
71
- },
72
- // Relaxations for config files
73
- {
74
- name: 'vortiquo/base/config-files',
72
+ name: '@vortiquo/base:config-files',
75
73
  files: [
76
74
  '**/*.config.{js,ts,mjs,cjs}',
77
75
  '**/.*rc.{js,ts,mjs,cjs}',
@@ -79,12 +77,11 @@ export const base = [
79
77
  '.lintstagedrc.*',
80
78
  ],
81
79
  rules: {
82
- // Config files require default exports
83
80
  'import/no-default-export': 'off',
84
- // Allow console in config files
85
81
  'no-console': 'off',
86
82
  },
87
83
  },
84
+ eslintConfigPrettier,
88
85
  ];
89
86
 
90
87
  export default base;
package/src/index.js ADDED
@@ -0,0 +1,25 @@
1
+ export { base } from './base/index.js';
2
+
3
+ // Next.js
4
+ export { nextjs } from './next/index.js';
5
+ export { nextjsStrict } from './next/strict.js';
6
+
7
+ // Node.js libraries
8
+ export { nodeLib } from './node-lib/index.js';
9
+ export { nodeLibStrict } from './node-lib/strict.js';
10
+
11
+ // React
12
+ export { react } from './react/index.js';
13
+ export { reactStrict } from './react/strict.js';
14
+
15
+ // React libraries
16
+ export { reactLib } from './react-lib/index.js';
17
+ export { reactLibStrict } from './react-lib/strict.js';
18
+
19
+ // Server (Express, Fastify, etc.)
20
+ export { server } from './server/index.js';
21
+ export { serverStrict } from './server/strict.js';
22
+
23
+ // TypeScript
24
+ export { baseTs } from './ts/index.js';
25
+ export { tsStrictTypeAware } from './ts/strict.js';
@@ -0,0 +1,52 @@
1
+ import nextPlugin from '@next/eslint-plugin-next';
2
+
3
+ import { react } from '../react/index.js';
4
+
5
+ /** @type {import("eslint").Linter.Config[]} */
6
+ export const nextjs = [
7
+ ...react,
8
+
9
+ {
10
+ name: '@vortiquo/nextjs',
11
+ files: ['**/*.{js,jsx,ts,tsx}'],
12
+ plugins: {
13
+ '@next/next': nextPlugin,
14
+ },
15
+ rules: {
16
+ ...nextPlugin.configs.recommended.rules,
17
+ ...nextPlugin.configs['core-web-vitals'].rules,
18
+ '@next/next/no-img-element': 'error',
19
+ '@next/next/no-html-link-for-pages': 'error',
20
+ },
21
+ },
22
+
23
+ {
24
+ name: '@vortiquo/nextjs:relax-default-export',
25
+ files: [
26
+ // App Router
27
+ '**/app/**/page.{js,jsx,ts,tsx}',
28
+ '**/app/**/layout.{js,jsx,ts,tsx}',
29
+ '**/app/**/loading.{js,jsx,ts,tsx}',
30
+ '**/app/**/error.{js,jsx,ts,tsx}',
31
+ '**/app/**/not-found.{js,jsx,ts,tsx}',
32
+ '**/app/**/route.{js,ts}',
33
+ '**/app/**/default.{js,jsx,ts,tsx}',
34
+ '**/app/**/template.{js,jsx,ts,tsx}',
35
+ '**/app/**/opengraph-image.{js,jsx,ts,tsx}',
36
+ '**/app/**/twitter-image.{js,jsx,ts,tsx}',
37
+ '**/app/**/sitemap.{js,ts}',
38
+ '**/app/**/robots.{js,ts}',
39
+ // Pages Router
40
+ '**/pages/**/*.{js,jsx,ts,tsx}',
41
+ // Middleware
42
+ '**/middleware.{js,ts}',
43
+ // Config
44
+ '**/*.config.{js,ts,mjs,cjs}',
45
+ ],
46
+ rules: {
47
+ 'import/no-default-export': 'off',
48
+ },
49
+ },
50
+ ];
51
+
52
+ export default nextjs;
@@ -0,0 +1,8 @@
1
+ import { reactStrict } from '../react/strict.js';
2
+ import { tsStrictTypeAware } from '../ts/strict.js';
3
+ import { nextjs } from './index.js';
4
+
5
+ /** @type {import("eslint").Linter.Config[]} */
6
+ export const nextjsStrict = [...nextjs, ...reactStrict, ...tsStrictTypeAware];
7
+
8
+ export default nextjsStrict;
@@ -0,0 +1,41 @@
1
+ import globals from 'globals';
2
+
3
+ import { base } from '../base/index.js';
4
+ import { baseTs, TS_FILES } from '../ts/index.js';
5
+
6
+ /** @type {import("eslint").Linter.Config[]} */
7
+ export const nodeLib = [
8
+ ...base,
9
+ ...baseTs,
10
+
11
+ {
12
+ name: '@vortiquo/node-lib:node-env',
13
+ languageOptions: {
14
+ globals: {
15
+ ...globals.node,
16
+ },
17
+ },
18
+ rules: {
19
+ 'no-console': 'error',
20
+ 'import/no-mutable-exports': 'error',
21
+ },
22
+ },
23
+
24
+ {
25
+ name: '@vortiquo/node-lib:scripts',
26
+ files: ['**/scripts/**/*.{js,cjs,mjs}'],
27
+ rules: {
28
+ 'no-console': 'off',
29
+ },
30
+ },
31
+
32
+ {
33
+ name: '@vortiquo/node-lib:ts',
34
+ files: TS_FILES,
35
+ rules: {
36
+ '@typescript-eslint/explicit-module-boundary-types': 'error',
37
+ },
38
+ },
39
+ ];
40
+
41
+ export default nodeLib;
@@ -0,0 +1,44 @@
1
+ import globals from 'globals';
2
+
3
+ import { base } from '../base/index.js';
4
+
5
+ /** @type {import("eslint").Linter.Config[]} */
6
+ export const nodeLibJs = [
7
+ ...base,
8
+
9
+ {
10
+ name: '@vortiquo/node-lib-js:files',
11
+ files: ['**/*.{js,cjs,mjs}'],
12
+ languageOptions: {
13
+ globals: {
14
+ ...globals.node,
15
+ },
16
+ ecmaVersion: 'latest',
17
+ sourceType: 'module',
18
+ },
19
+ rules: {
20
+ // Librería: idealmente sin logs
21
+ 'no-console': 'error',
22
+ },
23
+ },
24
+
25
+ // Permite console en scripts/ tooling
26
+ {
27
+ name: '@vortiquo/node-lib-js:scripts',
28
+ files: ['**/scripts/**/*.{js,cjs,mjs}'],
29
+ rules: {
30
+ 'no-console': 'off',
31
+ },
32
+ },
33
+
34
+ // Si la lib usa CJS en algunos archivos
35
+ {
36
+ name: '@vortiquo/node-lib-js:cjs',
37
+ files: ['**/*.cjs'],
38
+ languageOptions: {
39
+ sourceType: 'commonjs',
40
+ },
41
+ },
42
+ ];
43
+
44
+ export default nodeLibJs;
@@ -0,0 +1,44 @@
1
+ import globals from 'globals';
2
+
3
+ import { base } from '../base/index.js';
4
+
5
+ /** @type {import("eslint").Linter.Config[]} */
6
+ export const nodeLibJs = [
7
+ ...base,
8
+
9
+ {
10
+ name: '@vortiquo/node-lib-js:files',
11
+ files: ['**/*.{js,cjs,mjs}'],
12
+ languageOptions: {
13
+ globals: {
14
+ ...globals.node,
15
+ },
16
+ ecmaVersion: 'latest',
17
+ sourceType: 'module',
18
+ },
19
+ rules: {
20
+ // Librería: idealmente sin logs
21
+ 'no-console': 'error',
22
+ },
23
+ },
24
+
25
+ // Permite console en scripts/ tooling
26
+ {
27
+ name: '@vortiquo/node-lib-js:scripts',
28
+ files: ['**/scripts/**/*.{js,cjs,mjs}'],
29
+ rules: {
30
+ 'no-console': 'off',
31
+ },
32
+ },
33
+
34
+ // Si la lib usa CJS en algunos archivos
35
+ {
36
+ name: '@vortiquo/node-lib-js:cjs',
37
+ files: ['**/*.cjs'],
38
+ languageOptions: {
39
+ sourceType: 'commonjs',
40
+ },
41
+ },
42
+ ];
43
+
44
+ export default nodeLibJs;
@@ -0,0 +1,26 @@
1
+ import { TS_FILES } from '../ts/index.js';
2
+ import { tsStrictTypeAware } from '../ts/strict.js';
3
+ import { nodeLib } from './index.js';
4
+
5
+ /** @type {import("eslint").Linter.Config[]} */
6
+ export const nodeLibStrict = [
7
+ ...nodeLib,
8
+ ...tsStrictTypeAware,
9
+
10
+ {
11
+ name: '@vortiquo/node-lib:strict',
12
+ files: TS_FILES,
13
+ rules: {
14
+ '@typescript-eslint/no-floating-promises': 'error',
15
+ '@typescript-eslint/no-misused-promises': [
16
+ 'error',
17
+ { checksVoidReturn: { attributes: false } },
18
+ ],
19
+ '@typescript-eslint/await-thenable': 'error',
20
+
21
+ '@typescript-eslint/no-unnecessary-condition': 'error',
22
+ },
23
+ },
24
+ ];
25
+
26
+ export default nodeLibStrict;
@@ -1,18 +1,17 @@
1
1
  import reactPlugin from 'eslint-plugin-react';
2
2
  import reactHooksPlugin from 'eslint-plugin-react-hooks';
3
3
  import globals from 'globals';
4
- import { baseTypescript } from './base-typescript.js';
5
4
 
6
- /**
7
- * ESLint configuration for React projects (libraries, components).
8
- * Extends TypeScript config with React-specific rules.
9
- *
10
- * @type {import("eslint").Linter.Config[]}
11
- */
5
+ import { base } from '../base/index.js';
6
+ import { baseTs } from '../ts/index.js';
7
+
8
+ /** @type {import("eslint").Linter.Config[]} */
12
9
  export const react = [
13
- ...baseTypescript,
10
+ ...base,
11
+ ...baseTs,
12
+
14
13
  {
15
- name: 'vortiquo/react',
14
+ name: '@vortiquo/react',
16
15
  files: ['**/*.{jsx,tsx}'],
17
16
  plugins: {
18
17
  react: reactPlugin,
@@ -23,25 +22,19 @@ export const react = [
23
22
  ...globals.browser,
24
23
  },
25
24
  parserOptions: {
26
- ecmaFeatures: {
27
- jsx: true,
28
- },
25
+ ecmaFeatures: { jsx: true },
29
26
  },
30
27
  },
31
28
  settings: {
32
- react: {
33
- version: 'detect',
34
- },
29
+ react: { version: 'detect' },
35
30
  },
36
31
  rules: {
37
- // React recommended
32
+ // React recommended + JSX runtime (React 17+)
38
33
  ...reactPlugin.configs.recommended.rules,
39
34
  ...reactPlugin.configs['jsx-runtime'].rules,
40
35
 
41
- // React Hooks
36
+ // React Hooks recommended (includes rules-of-hooks + exhaustive-deps)
42
37
  ...reactHooksPlugin.configs.recommended.rules,
43
-
44
- // React preferences
45
38
  'react/prop-types': 'off',
46
39
  'react/jsx-no-target-blank': 'error',
47
40
  'react/jsx-curly-brace-presence': [
@@ -51,22 +44,14 @@ export const react = [
51
44
  'react/self-closing-comp': 'error',
52
45
  'react/jsx-sort-props': [
53
46
  'warn',
54
- {
55
- callbacksLast: true,
56
- shorthandFirst: true,
57
- reservedFirst: true,
58
- },
47
+ { callbacksLast: true, shorthandFirst: true, reservedFirst: true },
59
48
  ],
60
49
 
61
- // Hooks
62
- 'react-hooks/rules-of-hooks': 'error',
63
- 'react-hooks/exhaustive-deps': 'warn',
64
-
65
- // TypeScript handles these
50
+ // TypeScript handles prop types and defaults better
66
51
  'react/require-default-props': 'off',
67
52
  'react/jsx-props-no-spreading': 'off',
68
53
 
69
- // Allow explicit return types to be optional for React components
54
+ // In React components you typically don't want to enforce return types
70
55
  '@typescript-eslint/explicit-function-return-type': 'off',
71
56
  },
72
57
  },
@@ -0,0 +1,15 @@
1
+ import { react } from './index.js';
2
+
3
+ /** @type {import("eslint").Linter.Config[]} */
4
+ export const reactStrict = [
5
+ ...react,
6
+ {
7
+ name: '@vortiquo/react:strict',
8
+ files: ['**/*.{jsx,tsx}'],
9
+ rules: {
10
+ 'react-hooks/exhaustive-deps': 'error',
11
+ },
12
+ },
13
+ ];
14
+
15
+ export default reactStrict;
@@ -0,0 +1,86 @@
1
+ import reactPlugin from 'eslint-plugin-react';
2
+ import reactHooksPlugin from 'eslint-plugin-react-hooks';
3
+ import globals from 'globals';
4
+
5
+ import { base } from '../base/index.js';
6
+ import { baseTs, TS_FILES } from '../ts/index.js';
7
+
8
+ /** @type {import("eslint").Linter.Config[]} */
9
+ export const reactLib = [
10
+ ...base,
11
+ ...baseTs,
12
+
13
+ {
14
+ name: '@vortiquo/react-lib:react',
15
+ files: ['**/*.{jsx,tsx}'],
16
+ plugins: {
17
+ react: reactPlugin,
18
+ 'react-hooks': reactHooksPlugin,
19
+ },
20
+ languageOptions: {
21
+ globals: {
22
+ ...globals.browser,
23
+ },
24
+ parserOptions: {
25
+ ecmaFeatures: { jsx: true },
26
+ },
27
+ },
28
+ settings: {
29
+ react: { version: 'detect' },
30
+ },
31
+ rules: {
32
+ // React core
33
+ ...reactPlugin.configs.recommended.rules,
34
+ ...reactPlugin.configs['jsx-runtime'].rules,
35
+
36
+ // Hooks
37
+ ...reactHooksPlugin.configs.recommended.rules,
38
+
39
+ // Libraries should not log
40
+ 'no-console': 'error',
41
+
42
+ // No prop-types in TS libs
43
+ 'react/prop-types': 'off',
44
+
45
+ // Clean JSX
46
+ 'react/self-closing-comp': 'error',
47
+ 'react/jsx-curly-brace-presence': [
48
+ 'error',
49
+ { props: 'never', children: 'never' },
50
+ ],
51
+
52
+ // Allow spreads (very common in component APIs)
53
+ 'react/jsx-props-no-spreading': 'off',
54
+
55
+ // TS handles this better
56
+ 'react/require-default-props': 'off',
57
+ '@typescript-eslint/explicit-function-return-type': 'off',
58
+ },
59
+ },
60
+
61
+ {
62
+ name: '@vortiquo/react-lib:style',
63
+ files: ['src/**/*.{ts,tsx}'],
64
+ rules: {
65
+ '@typescript-eslint/consistent-type-definitions': ['error', 'interface'],
66
+ },
67
+ },
68
+
69
+ // TypeScript-specific expectations for libs
70
+ {
71
+ name: '@vortiquo/react-lib:ts',
72
+ files: TS_FILES,
73
+ rules: {
74
+ // Exported APIs should be explicit
75
+ '@typescript-eslint/explicit-module-boundary-types': 'error',
76
+
77
+ // Types should be clean and reusable
78
+ '@typescript-eslint/consistent-type-exports': [
79
+ 'error',
80
+ { fixMixedExportsWithInlineTypeSpecifier: true },
81
+ ],
82
+ },
83
+ },
84
+ ];
85
+
86
+ export default reactLib;
@@ -0,0 +1,30 @@
1
+ import { TS_FILES } from '../ts/index.js';
2
+ import { tsStrictTypeAware } from '../ts/strict.js';
3
+ import { reactLib } from './index.js';
4
+
5
+ /** @type {import("eslint").Linter.Config[]} */
6
+ export const reactLibStrict = [
7
+ ...reactLib,
8
+ ...tsStrictTypeAware,
9
+
10
+ {
11
+ name: '@vortiquo/react-lib:strict',
12
+ files: TS_FILES,
13
+ rules: {
14
+ // Promise safety (important even in UI libs)
15
+ '@typescript-eslint/no-floating-promises': 'error',
16
+ '@typescript-eslint/no-misused-promises': [
17
+ 'error',
18
+ { checksVoidReturn: { attributes: false } },
19
+ ],
20
+ '@typescript-eslint/await-thenable': 'error',
21
+
22
+ // Catch subtle API bugs
23
+ '@typescript-eslint/no-unnecessary-condition': 'error',
24
+ '@typescript-eslint/switch-exhaustiveness-check': 'error',
25
+ '@typescript-eslint/no-explicit-any': 'error',
26
+ },
27
+ },
28
+ ];
29
+
30
+ export default reactLibStrict;
@@ -0,0 +1,37 @@
1
+ import globals from 'globals';
2
+
3
+ import { base } from '../base/index.js';
4
+ import { baseTs, TS_FILES } from '../ts/index.js';
5
+
6
+ /** @type {import("eslint").Linter.Config[]} */
7
+ export const server = [
8
+ ...base,
9
+ ...baseTs,
10
+
11
+ {
12
+ name: '@vortiquo/server:node-env',
13
+ languageOptions: {
14
+ globals: {
15
+ ...globals.node,
16
+ },
17
+ },
18
+ rules: {
19
+ 'no-console': 'off',
20
+ 'no-process-exit': 'off',
21
+ },
22
+ },
23
+
24
+ {
25
+ name: '@vortiquo/server:ts-rules',
26
+ files: TS_FILES,
27
+ rules: {
28
+ '@typescript-eslint/explicit-function-return-type': 'error',
29
+ '@typescript-eslint/explicit-module-boundary-types': 'error',
30
+
31
+ '@typescript-eslint/require-await': 'error',
32
+ '@typescript-eslint/promise-function-async': 'error',
33
+ },
34
+ },
35
+ ];
36
+
37
+ export default server;
@@ -0,0 +1,24 @@
1
+ import { TS_FILES } from '../ts/index.js';
2
+ import { tsStrictTypeAware } from '../ts/strict.js';
3
+ import { server } from './index.js';
4
+
5
+ /** @type {import("eslint").Linter.Config[]} */
6
+ export const serverStrict = [
7
+ ...server,
8
+ ...tsStrictTypeAware,
9
+
10
+ {
11
+ name: '@vortiquo/server:strict-extras',
12
+ files: TS_FILES,
13
+ rules: {
14
+ '@typescript-eslint/no-floating-promises': 'error',
15
+ '@typescript-eslint/no-misused-promises': [
16
+ 'error',
17
+ { checksVoidReturn: { attributes: false } },
18
+ ],
19
+ '@typescript-eslint/await-thenable': 'error',
20
+ },
21
+ },
22
+ ];
23
+
24
+ export default serverStrict;
@@ -0,0 +1,68 @@
1
+ import tseslint from 'typescript-eslint';
2
+
3
+ export const TS_FILES = ['**/*.{ts,tsx,mts,cts}'];
4
+
5
+ /** @type {import("eslint").Linter.Config[]} */
6
+ export const baseTs = [
7
+ {
8
+ name: '@vortiquo/ts:core',
9
+ files: TS_FILES,
10
+ languageOptions: {
11
+ parser: tseslint.parser,
12
+ parserOptions: {
13
+ ecmaVersion: 'latest',
14
+ sourceType: 'module',
15
+ },
16
+ },
17
+ plugins: {
18
+ '@typescript-eslint': tseslint.plugin,
19
+ },
20
+ rules: {
21
+ 'no-unused-vars': 'off',
22
+ '@typescript-eslint/no-unused-vars': [
23
+ 'error',
24
+ {
25
+ argsIgnorePattern: '^_',
26
+ varsIgnorePattern: '^_',
27
+ caughtErrorsIgnorePattern: '^_',
28
+ ignoreRestSiblings: true,
29
+ },
30
+ ],
31
+
32
+ '@typescript-eslint/consistent-type-imports': [
33
+ 'error',
34
+ { prefer: 'type-imports', fixStyle: 'separate-type-imports' },
35
+ ],
36
+
37
+ '@typescript-eslint/no-explicit-any': 'warn',
38
+ '@typescript-eslint/ban-ts-comment': [
39
+ 'error',
40
+ {
41
+ 'ts-expect-error': 'allow-with-description',
42
+ minimumDescriptionLength: 5,
43
+ },
44
+ ],
45
+ },
46
+ },
47
+
48
+ {
49
+ name: '@vortiquo/ts:style',
50
+ files: TS_FILES,
51
+ rules: {
52
+ '@typescript-eslint/consistent-type-definitions': ['error', 'type'],
53
+ },
54
+ },
55
+
56
+ // Relax rules for config files
57
+ {
58
+ name: '@vortiquo/ts:config-files',
59
+ files: ['**/*.config.{ts,mts,cts}', '**/.*rc.{ts,mts,cts}'],
60
+ rules: {
61
+ '@typescript-eslint/no-explicit-any': 'off',
62
+ 'no-console': 'off',
63
+ 'import/no-default-export': 'off',
64
+ },
65
+ },
66
+ ];
67
+
68
+ export default baseTs;
@@ -0,0 +1,55 @@
1
+ import tseslint from 'typescript-eslint';
2
+
3
+ import { TS_FILES } from './index.js';
4
+
5
+ /** @type {import("eslint").Linter.Config[]} */
6
+ export const tsStrictTypeAware = [
7
+ {
8
+ name: '@vortiquo/ts:type-aware',
9
+ files: TS_FILES,
10
+ languageOptions: {
11
+ parserOptions: {
12
+ projectService: true,
13
+ },
14
+ },
15
+ },
16
+
17
+ ...tseslint.configs.strictTypeChecked.map((cfg) => ({
18
+ ...cfg,
19
+ name: cfg.name ? `@vortiquo/ts:strict/${cfg.name}` : '@vortiquo/ts:strict',
20
+ files: TS_FILES,
21
+ })),
22
+
23
+ ...tseslint.configs.stylisticTypeChecked.map((cfg) => ({
24
+ ...cfg,
25
+ name: cfg.name
26
+ ? `@vortiquo/ts:stylistic/${cfg.name}`
27
+ : '@vortiquo/ts:stylistic',
28
+ files: TS_FILES,
29
+ })),
30
+
31
+ {
32
+ name: '@vortiquo/ts:strict-extras',
33
+ files: TS_FILES,
34
+ rules: {
35
+ '@typescript-eslint/restrict-template-expressions': [
36
+ 'error',
37
+ {
38
+ allowNumber: true,
39
+ allowBoolean: true,
40
+ allowNullish: false,
41
+ },
42
+ ],
43
+ '@typescript-eslint/no-floating-promises': 'error',
44
+ '@typescript-eslint/no-misused-promises': [
45
+ 'error',
46
+ { checksVoidReturn: { attributes: false } },
47
+ ],
48
+ '@typescript-eslint/await-thenable': 'error',
49
+ '@typescript-eslint/switch-exhaustiveness-check': 'error',
50
+ '@typescript-eslint/no-unnecessary-condition': 'error',
51
+ },
52
+ },
53
+ ];
54
+
55
+ export default tsStrictTypeAware;
@@ -1,167 +0,0 @@
1
- import tseslint from 'typescript-eslint';
2
- import { base } from './base.js';
3
-
4
- /**
5
- * TypeScript file patterns - type-aware rules only apply to these
6
- */
7
- const TS_FILES = ['**/*.ts', '**/*.tsx', '**/*.mts', '**/*.cts'];
8
-
9
- /**
10
- * Base TypeScript ESLint configuration.
11
- * Extends base config with TypeScript-specific rules.
12
- *
13
- * Type-aware rules are ONLY applied to TypeScript files (.ts, .tsx, .mts, .cts).
14
- * JavaScript files (including config files like eslint.config.js) are not affected.
15
- *
16
- * @type {import("eslint").Linter.Config[]}
17
- */
18
- export const baseTypescript = [
19
- ...base,
20
-
21
- // Global TypeScript plugin registration (plugins must be defined globally)
22
- {
23
- name: 'vortiquo/typescript-plugins',
24
- plugins: {
25
- '@typescript-eslint': tseslint.plugin,
26
- },
27
- },
28
-
29
- // Allow relative imports in config files (only applies to TS files since
30
- // no-restricted-imports is only defined in base-typescript)
31
- {
32
- name: 'vortiquo/typescript/config-files',
33
- files: ['**/*.config.ts', '**/*.config.mts', '**/*.config.cts'],
34
- languageOptions: {
35
- parser: tseslint.parser,
36
- parserOptions: {
37
- projectService: false, // Config files don't need full project analysis
38
- },
39
- },
40
- rules: {
41
- // Inherit base config file rules
42
- 'import/no-default-export': 'off',
43
- 'no-console': 'off',
44
- // TypeScript-specific overrides
45
- 'no-restricted-imports': 'off',
46
- '@typescript-eslint/no-unsafe-assignment': 'off',
47
- },
48
- },
49
-
50
- // TypeScript parser and language options (scoped to TS files, excluding config files)
51
- {
52
- name: 'vortiquo/typescript-parser',
53
- files: TS_FILES,
54
- ignores: ['**/*.config.ts', '**/*.config.mts', '**/*.config.cts'],
55
- languageOptions: {
56
- parser: tseslint.parser,
57
- parserOptions: {
58
- projectService: true,
59
- },
60
- },
61
- },
62
-
63
- // Apply type-checked rules ONLY to TypeScript files
64
- // Apply strict type-checked rules to TS files
65
- ...tseslint.configs.strictTypeChecked.map((config) => ({
66
- ...config,
67
- files: TS_FILES,
68
- })),
69
- // Apply stylistic type-checked rules to TS files
70
- ...tseslint.configs.stylisticTypeChecked.map((config) => ({
71
- ...config,
72
- files: TS_FILES,
73
- })),
74
-
75
- // TypeScript-specific settings and rules (only for TS files)
76
- {
77
- name: 'vortiquo/typescript',
78
- files: TS_FILES,
79
- languageOptions: {
80
- parserOptions: {
81
- projectService: true,
82
- },
83
- },
84
- settings: {
85
- 'import/resolver': {
86
- typescript: true,
87
- node: true,
88
- },
89
- },
90
- rules: {
91
- // Override base no-unused-vars with TypeScript version
92
- 'no-unused-vars': 'off',
93
- '@typescript-eslint/no-unused-vars': [
94
- 'error',
95
- {
96
- argsIgnorePattern: '^_',
97
- varsIgnorePattern: '^_',
98
- caughtErrorsIgnorePattern: '^_',
99
- },
100
- ],
101
-
102
- // Type imports (enforces `import type` for types - better tree-shaking)
103
- '@typescript-eslint/consistent-type-imports': [
104
- 'error',
105
- { prefer: 'type-imports', fixStyle: 'separate-type-imports' },
106
- ],
107
- '@typescript-eslint/consistent-type-exports': [
108
- 'error',
109
- { fixMixedExportsWithInlineTypeSpecifier: true },
110
- ],
111
-
112
- // Strictness - catch bugs early
113
- '@typescript-eslint/no-explicit-any': 'error',
114
- '@typescript-eslint/no-use-before-define': [
115
- 'error',
116
- { functions: false, classes: true, variables: true },
117
- ],
118
- '@typescript-eslint/explicit-function-return-type': [
119
- 'error',
120
- {
121
- allowExpressions: true,
122
- allowTypedFunctionExpressions: true,
123
- allowHigherOrderFunctions: true,
124
- },
125
- ],
126
- '@typescript-eslint/no-misused-promises': [
127
- 'error',
128
- { checksVoidReturn: { attributes: false } },
129
- ],
130
- '@typescript-eslint/no-floating-promises': 'error',
131
- '@typescript-eslint/await-thenable': 'error',
132
-
133
- // Preferences
134
- '@typescript-eslint/consistent-type-definitions': ['error', 'type'],
135
- '@typescript-eslint/array-type': ['error', { default: 'array-simple' }],
136
- '@typescript-eslint/prefer-nullish-coalescing': 'error',
137
- '@typescript-eslint/prefer-optional-chain': 'error',
138
- '@typescript-eslint/no-unnecessary-condition': 'error',
139
- '@typescript-eslint/switch-exhaustiveness-check': 'error',
140
-
141
- // Relaxations (good DX without sacrificing safety)
142
- '@typescript-eslint/no-confusing-void-expression': 'off',
143
- '@typescript-eslint/restrict-template-expressions': [
144
- 'error',
145
- { allowNumber: true, allowBoolean: true },
146
- ],
147
- // This one is too strict - TS already handles this well
148
- '@typescript-eslint/require-await': 'off',
149
-
150
- // Enforce absolute imports (use tsconfig paths instead of relative)
151
- 'no-restricted-imports': [
152
- 'error',
153
- {
154
- patterns: [
155
- {
156
- group: ['src/**/*', '../**/*'],
157
- message:
158
- 'Usage of src/* and ../**/* imports is not allowed, use paths defined in tsconfig',
159
- },
160
- ],
161
- },
162
- ],
163
- },
164
- },
165
- ];
166
-
167
- export default baseTypescript;
package/index.js DELETED
@@ -1,11 +0,0 @@
1
- // Re-export all configs for convenience
2
- export { base } from './base.js';
3
- export { baseTypescript } from './base-typescript.js';
4
- export { react } from './react.js';
5
- export { reactLibrary } from './react-library.js';
6
- export { reactLibraryJs } from './react-library-js.js';
7
- export { nextjs } from './nextjs.js';
8
- export { server } from './server.js';
9
- export { nestjs } from './nestjs.js';
10
- export { nodeLibrary } from './node-library.js';
11
- export { nodeLibraryJs } from './node-library-js.js';
package/nestjs.js DELETED
@@ -1,43 +0,0 @@
1
- import { server } from './server.js';
2
-
3
- /**
4
- * ESLint configuration for NestJS applications.
5
- * Extends server config with NestJS-specific rules.
6
- *
7
- * @type {import("eslint").Linter.Config[]}
8
- */
9
- export const nestjs = [
10
- ...server,
11
- {
12
- name: 'vortiquo/nestjs',
13
- rules: {
14
- // NestJS uses classes extensively
15
- '@typescript-eslint/consistent-type-definitions': 'off',
16
-
17
- // NestJS uses empty constructors for DI
18
- '@typescript-eslint/no-empty-function': [
19
- 'error',
20
- { allow: ['constructors'] },
21
- ],
22
-
23
- // NestJS decorators often require classes
24
- '@typescript-eslint/no-extraneous-class': 'off',
25
-
26
- // NestJS uses parameter properties
27
- '@typescript-eslint/parameter-properties': 'off',
28
-
29
- // Allow unused vars in decorators (common pattern)
30
- '@typescript-eslint/no-unused-vars': [
31
- 'error',
32
- {
33
- argsIgnorePattern: '^_',
34
- varsIgnorePattern: '^_',
35
- caughtErrorsIgnorePattern: '^_',
36
- args: 'after-used',
37
- },
38
- ],
39
- },
40
- },
41
- ];
42
-
43
- export default nestjs;
package/nextjs.js DELETED
@@ -1,51 +0,0 @@
1
- import nextPlugin from '@next/eslint-plugin-next';
2
- import { react } from './react.js';
3
-
4
- /**
5
- * ESLint configuration for Next.js applications.
6
- * Extends React config with Next.js-specific rules.
7
- *
8
- * @type {import("eslint").Linter.Config[]}
9
- */
10
- export const nextjs = [
11
- ...react,
12
- {
13
- name: 'vortiquo/nextjs',
14
- plugins: {
15
- '@next/next': nextPlugin,
16
- },
17
- rules: {
18
- ...nextPlugin.configs.recommended.rules,
19
- ...nextPlugin.configs['core-web-vitals'].rules,
20
-
21
- // Next.js specific
22
- '@next/next/no-html-link-for-pages': 'error',
23
- '@next/next/no-img-element': 'error',
24
- },
25
- },
26
- {
27
- name: 'vortiquo/nextjs/relaxations',
28
- files: [
29
- '**/app/**/page.tsx',
30
- '**/app/**/layout.tsx',
31
- '**/app/**/loading.tsx',
32
- '**/app/**/error.tsx',
33
- '**/app/**/not-found.tsx',
34
- '**/app/**/route.ts',
35
- '**/app/**/default.tsx',
36
- '**/app/**/template.tsx',
37
- '**/app/**/opengraph-image.tsx',
38
- '**/app/**/twitter-image.tsx',
39
- '**/app/**/sitemap.ts',
40
- '**/app/**/robots.ts',
41
- '**/middleware.ts',
42
- '**/*.config.{js,ts,mjs}',
43
- ],
44
- rules: {
45
- // Next.js requires default exports for these files
46
- 'import/no-default-export': 'off',
47
- },
48
- },
49
- ];
50
-
51
- export default nextjs;
@@ -1,26 +0,0 @@
1
- import globals from 'globals';
2
- import { base } from './base.js';
3
-
4
- /**
5
- * ESLint configuration for JavaScript Node.js libraries/packages.
6
- * For projects without TypeScript - extends base config only.
7
- *
8
- * @type {import("eslint").Linter.Config[]}
9
- */
10
- export const nodeLibraryJs = [
11
- ...base,
12
- {
13
- name: 'vortiquo/node-library-js',
14
- languageOptions: {
15
- globals: {
16
- ...globals.node,
17
- },
18
- },
19
- rules: {
20
- // No console in libraries (consumers should handle logging)
21
- 'no-console': 'error',
22
- },
23
- },
24
- ];
25
-
26
- export default nodeLibraryJs;
package/node-library.js DELETED
@@ -1,44 +0,0 @@
1
- import globals from 'globals';
2
- import { baseTypescript } from './base-typescript.js';
3
-
4
- /**
5
- * TypeScript file patterns - type-aware rules only apply to these
6
- */
7
- const TS_FILES = ['**/*.ts', '**/*.tsx', '**/*.mts', '**/*.cts'];
8
-
9
- /**
10
- * ESLint configuration for Node.js libraries/packages.
11
- * Extends TypeScript config for shared backend packages.
12
- *
13
- * @type {import("eslint").Linter.Config[]}
14
- */
15
- export const nodeLibrary = [
16
- ...baseTypescript,
17
- {
18
- name: 'vortiquo/node-library',
19
- languageOptions: {
20
- globals: {
21
- ...globals.node,
22
- },
23
- },
24
- rules: {
25
- // No console in libraries (consumers should handle logging)
26
- 'no-console': 'error',
27
- },
28
- },
29
- {
30
- name: 'vortiquo/node-library/typescript',
31
- files: TS_FILES,
32
- rules: {
33
- // Libraries should be strict
34
- '@typescript-eslint/explicit-function-return-type': 'error',
35
- '@typescript-eslint/explicit-module-boundary-types': 'error',
36
-
37
- // Async handling
38
- '@typescript-eslint/no-floating-promises': 'error',
39
- '@typescript-eslint/require-await': 'error',
40
- },
41
- },
42
- ];
43
-
44
- export default nodeLibrary;
@@ -1,72 +0,0 @@
1
- import reactPlugin from 'eslint-plugin-react';
2
- import reactHooksPlugin from 'eslint-plugin-react-hooks';
3
- import globals from 'globals';
4
- import { base } from './base.js';
5
-
6
- /**
7
- * ESLint configuration for JavaScript React libraries/components.
8
- * For projects without TypeScript - extends base config only.
9
- *
10
- * @type {import("eslint").Linter.Config[]}
11
- */
12
- export const reactLibraryJs = [
13
- ...base,
14
- {
15
- name: 'vortiquo/react-library-js',
16
- files: ['**/*.{js,jsx,mjs,cjs}'],
17
- plugins: {
18
- react: reactPlugin,
19
- 'react-hooks': reactHooksPlugin,
20
- },
21
- languageOptions: {
22
- globals: {
23
- ...globals.browser,
24
- },
25
- parserOptions: {
26
- ecmaFeatures: {
27
- jsx: true,
28
- },
29
- },
30
- },
31
- settings: {
32
- react: {
33
- version: 'detect',
34
- },
35
- },
36
- rules: {
37
- // React recommended
38
- ...reactPlugin.configs.recommended.rules,
39
- ...reactPlugin.configs['jsx-runtime'].rules,
40
-
41
- // React Hooks
42
- ...reactHooksPlugin.configs.recommended.rules,
43
-
44
- // React preferences
45
- 'react/prop-types': 'off',
46
- 'react/jsx-no-target-blank': 'error',
47
- 'react/jsx-curly-brace-presence': [
48
- 'error',
49
- { props: 'never', children: 'never' },
50
- ],
51
- 'react/self-closing-comp': 'error',
52
- 'react/jsx-sort-props': [
53
- 'warn',
54
- {
55
- callbacksLast: true,
56
- shorthandFirst: true,
57
- reservedFirst: true,
58
- },
59
- ],
60
-
61
- // Hooks
62
- 'react-hooks/rules-of-hooks': 'error',
63
- 'react-hooks/exhaustive-deps': 'warn',
64
-
65
- // Not needed without TypeScript
66
- 'react/require-default-props': 'off',
67
- 'react/jsx-props-no-spreading': 'off',
68
- },
69
- },
70
- ];
71
-
72
- export default reactLibraryJs;
package/react-library.js DELETED
@@ -1,36 +0,0 @@
1
- import { react } from './react.js';
2
-
3
- /**
4
- * TypeScript file patterns - type-aware rules only apply to these
5
- */
6
- const TS_FILES = ['**/*.ts', '**/*.tsx', '**/*.mts', '**/*.cts'];
7
-
8
- /**
9
- * ESLint configuration for React component libraries.
10
- * Extends React config with library-specific rules.
11
- *
12
- * @type {import("eslint").Linter.Config[]}
13
- */
14
- export const reactLibrary = [
15
- ...react,
16
- {
17
- name: 'vortiquo/react-library',
18
- rules: {
19
- // No console in libraries
20
- 'no-console': 'error',
21
-
22
- // Prefer named exports for tree-shaking
23
- 'import/no-default-export': 'error',
24
- },
25
- },
26
- {
27
- name: 'vortiquo/react-library/typescript',
28
- files: TS_FILES,
29
- rules: {
30
- // Libraries should be stricter about exports
31
- '@typescript-eslint/explicit-module-boundary-types': 'error',
32
- },
33
- },
34
- ];
35
-
36
- export default reactLibrary;
package/server.js DELETED
@@ -1,49 +0,0 @@
1
- import globals from 'globals';
2
- import { baseTypescript } from './base-typescript.js';
3
-
4
- /**
5
- * TypeScript file patterns - type-aware rules only apply to these
6
- */
7
- const TS_FILES = ['**/*.ts', '**/*.tsx', '**/*.mts', '**/*.cts'];
8
-
9
- /**
10
- * ESLint configuration for backend APIs (Fastify, Express, Hono).
11
- * Extends TypeScript config with Node.js-specific rules.
12
- *
13
- * @type {import("eslint").Linter.Config[]}
14
- */
15
- export const server = [
16
- ...baseTypescript,
17
- {
18
- name: 'vortiquo/server',
19
- languageOptions: {
20
- globals: {
21
- ...globals.node,
22
- },
23
- },
24
- rules: {
25
- // Allow console in backend
26
- 'no-console': 'off',
27
-
28
- // Backend-specific rules
29
- 'no-process-exit': 'off',
30
- },
31
- },
32
- {
33
- name: 'vortiquo/server/typescript',
34
- files: TS_FILES,
35
- rules: {
36
- // Stricter for backend code
37
- '@typescript-eslint/explicit-function-return-type': 'error',
38
- '@typescript-eslint/explicit-module-boundary-types': 'error',
39
-
40
- // Async handling
41
- '@typescript-eslint/no-floating-promises': 'error',
42
- '@typescript-eslint/require-await': 'error',
43
- '@typescript-eslint/await-thenable': 'error',
44
- '@typescript-eslint/promise-function-async': 'error',
45
- },
46
- },
47
- ];
48
-
49
- export default server;