@vijayhardaha/dev-config 1.1.3 → 2.0.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/README.md CHANGED
@@ -6,6 +6,8 @@
6
6
 
7
7
  Reusable development configuration package for Next.js + TypeScript projects.
8
8
 
9
+ > **v2.0.0** — Requires ESLint >=10. Native flat config only. No FlatCompat.
10
+
9
11
  ## Features
10
12
 
11
13
  - **ESLint** - Modular flat config with support for JavaScript, TypeScript, React, and Next.js
@@ -19,59 +21,66 @@ Reusable development configuration package for Next.js + TypeScript projects.
19
21
  ## Installation
20
22
 
21
23
  ```bash
22
- bun install @vijayhardaha/dev-config --save-dev
24
+ bun install @vijayhardaha/dev-config --dev
23
25
  ```
24
26
 
25
27
  ### Install Required Packages
26
28
 
27
29
  ```bash
28
- bun add --save-dev eslint@9.39.4 @eslint/js@9.39.4 prettier @prettier/plugin-xml @eslint/compat @eslint/eslintrc eslint-config-prettier eslint-plugin-prettier globals eslint-plugin-jsdoc eslint-plugin-import eslint-import-resolver-typescript typescript @typescript-eslint/eslint-plugin @typescript-eslint/parser
30
+ bun add --dev eslint prettier @prettier/plugin-xml eslint-plugin-prettier globals eslint-plugin-jsdoc eslint-plugin-import-x typescript typescript-eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser
29
31
  ```
30
32
 
31
33
  ### Install Optional Packages
32
34
 
33
- ### Typescript
34
-
35
- ```bash
36
- bun add --save-dev typescript @typescript-eslint/eslint-plugin @typescript-eslint/parser
37
- ```
38
-
39
- ### Prettier
40
-
41
- ```bash
42
- bun add --save-dev prettier @prettier/plugin-xml
43
- ```
44
-
45
35
  #### Stylelint
46
36
 
47
37
  ```bash
48
- bun add --save-dev stylelint stylelint-config-property-sort-order-smacss stylelint-config-standard-scss stylelint-order
38
+ bun add --dev stylelint stylelint-config-property-sort-order-smacss stylelint-config-standard-scss stylelint-order
49
39
  ```
50
40
 
51
41
  #### React
52
42
 
53
43
  ```bash
54
- bun add --save-dev eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-jsx-a11y
44
+ bun add --dev eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-jsx-a11y
55
45
  ```
56
46
 
57
47
  #### Next.js
58
48
 
59
49
  ```bash
60
- bun add --save-dev @next/eslint-plugin-next@15.5.15 eslint-config-next@15.5.15
50
+ bun add --dev @next/eslint-plugin-next eslint-config-next
61
51
  ```
62
52
 
63
53
  #### Commitlint
64
54
 
65
55
  ```bash
66
- bun add --save-dev husky @commitlint/cli @commitlint/config-conventional @commitlint/types
56
+ bun add --dev husky @commitlint/cli @commitlint/config-conventional @commitlint/types
67
57
  ```
68
58
 
69
59
  #### Next Sitemap
70
60
 
71
61
  ```bash
72
- bun add --save-dev next-sitemap
62
+ bun add --dev next-sitemap
73
63
  ```
74
64
 
65
+ ## Migrating from v1
66
+
67
+ v2 drops FlatCompat and uses native ESLint 10 flat configs throughout.
68
+
69
+ ### What changed
70
+
71
+ - **ESLint 10 required** — no longer compatible with ESLint 8/9
72
+ - **No FlatCompat** — all configs import flat config arrays/objects directly
73
+ - **`eslint-plugin-import` → `eslint-plugin-import-x`** — the ESLint 10-compatible fork
74
+ - **`eslint-config-prettier` removed** — bundled in `eslint-plugin-prettier/recommended`
75
+ - **`@eslint/js` removed** — no longer needed without FlatCompat
76
+ - **`plugins` option now accepts flat config arrays/objects** — no string-based plugin names
77
+
78
+ ### Required updates
79
+
80
+ 1. Install ESLint 10+: `bun add --dev eslint@10`
81
+ 2. Replace `eslint-plugin-import` with `eslint-plugin-import-x`
82
+ 3. Remove unused deps: `@eslint/compat`, `@eslint/eslintrc`, `@eslint/js`, `eslint-config-prettier`, `eslint-import-resolver-typescript`
83
+
75
84
  ## Quick Start
76
85
 
77
86
  ### ESLint
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vijayhardaha/dev-config",
3
- "version": "1.1.3",
3
+ "version": "2.0.0",
4
4
  "description": "Reusable development configurations for Next.js + TypeScript projects",
5
5
  "scripts": {
6
6
  "lint": "eslint .",
@@ -58,12 +58,11 @@
58
58
  "typescript"
59
59
  ],
60
60
  "devDependencies": {
61
- "@commitlint/cli": "^21.0.1",
62
- "@commitlint/config-conventional": "^21.0.1",
61
+ "@commitlint/cli": "^21.0.2",
62
+ "@commitlint/config-conventional": "^21.0.2",
63
63
  "@commitlint/types": "^21.0.1",
64
- "@prettier/plugin-xml": "^3.4.2",
65
- "@vijayhardaha/dev-config": "^1.1.2",
66
64
  "@vitest/coverage-v8": "^4.1.7",
65
+ "eslint-config-next": "^16.2.6",
67
66
  "eslint-plugin-jsx-a11y": "^6.10.2",
68
67
  "eslint-plugin-react": "^7.37.5",
69
68
  "eslint-plugin-react-hooks": "^7.1.1",
@@ -73,26 +72,24 @@
73
72
  "stylelint-config-property-sort-order-smacss": "^11.2.0",
74
73
  "stylelint-config-standard-scss": "^17.0.0",
75
74
  "stylelint-order": "^8.1.1",
76
- "typescript": "^6.0.3",
77
75
  "vitest": "^4.1.7"
78
76
  },
77
+ "dependencies": {
78
+ "@eslint/compat": "^2.1.0"
79
+ },
79
80
  "peerDependencies": {
80
- "@eslint/compat": ">=2",
81
- "@eslint/eslintrc": ">=3",
82
- "@eslint/js": ">=9",
83
81
  "@prettier/plugin-xml": ">=3",
84
82
  "@typescript-eslint/eslint-plugin": ">=8",
85
83
  "@typescript-eslint/parser": ">=8",
86
- "eslint-config-prettier": ">=10",
87
- "eslint-import-resolver-typescript": ">=4",
88
- "eslint-plugin-import": ">=2",
84
+ "eslint": ">=10",
85
+ "eslint-plugin-import-x": ">=4",
89
86
  "eslint-plugin-jsdoc": ">=62",
90
87
  "eslint-plugin-prettier": ">=5",
91
- "eslint": ">=9",
92
88
  "globals": ">=17",
93
89
  "husky": ">=9",
94
90
  "prettier": "^3.8.3",
95
- "typescript": ">=6"
91
+ "typescript": ">=6",
92
+ "typescript-eslint": ">=8"
96
93
  },
97
94
  "peerDependenciesMeta": {
98
95
  "@commitlint/cli": {
@@ -9,9 +9,7 @@
9
9
  * =====================================================================
10
10
  */
11
11
 
12
- import { setup, buildConfig, files } from './lib/index.js';
13
-
14
- const { compat } = setup();
12
+ import { buildConfig, files } from './lib/index.js';
15
13
 
16
14
  /**
17
15
  * Creates an ESLint configuration object with optional features.
@@ -35,7 +33,6 @@ export const createConfig = (options = {}) => {
35
33
  const { prettier = true, importOrder = true, jsdoc = true } = options;
36
34
 
37
35
  return buildConfig({
38
- compat,
39
36
  files: [...files.withoutTs, ...(options.files || [])],
40
37
  options: { ...options, prettier, importOrder, jsdoc },
41
38
  });
@@ -1,4 +1,9 @@
1
+ import { fixupPluginRules } from '@eslint/compat';
1
2
  import { defineConfig } from 'eslint/config';
3
+ import importX from 'eslint-plugin-import-x';
4
+ import jsdocPlugin from 'eslint-plugin-jsdoc';
5
+ import prettierRecommended from 'eslint-plugin-prettier/recommended';
6
+ import tsEslint from 'typescript-eslint';
2
7
 
3
8
  import { globalIgnores } from './ignores.js';
4
9
  import { commonLanguageOptions } from './language-options.js';
@@ -9,10 +14,9 @@ import { commonParser } from './setup.js';
9
14
  * Builds a common ESLint configuration with support for various options.
10
15
  *
11
16
  * @param {object} config - Configuration options.
12
- * @param {object} config.compat - FlatCompat instance.
13
17
  * @param {string[]} config.files - File patterns to apply the config to.
14
- * @param {string[]} config.builtinPlugins - Plugin configs to always include (e.g., 'plugin:@typescript-eslint/recommended').
15
- * @param {object} config.conditionalPlugins - Conditional plugins based on options (e.g., { prettier: true, importOrder: true }).
18
+ * @param {(Array|object)[]} config.builtinPlugins - Flat config arrays or objects to always include.
19
+ * @param {object} config.conditionalPlugins - Conditional plugins based on options (e.g., { react: true, a11y: true }).
16
20
  * @param {object} [config.languageOptions] - Additional language options.
17
21
  * @param {object} [config.parserOptions] - Parser options.
18
22
  * @param {object} [config.settings] - Settings object.
@@ -23,7 +27,6 @@ import { commonParser } from './setup.js';
23
27
  * @returns {import('eslint').Linter.Config[]} ESLint configuration array.
24
28
  */
25
29
  export const buildConfig = ({
26
- compat,
27
30
  files: filePatterns,
28
31
  builtinPlugins = [],
29
32
  conditionalPlugins = {},
@@ -54,9 +57,9 @@ export const buildConfig = ({
54
57
 
55
58
  const builtPlugins = [
56
59
  ...builtinPlugins,
57
- importOrder && 'plugin:import/recommended',
58
- jsdoc && 'plugin:jsdoc/recommended',
59
- prettier && 'plugin:prettier/recommended',
60
+ importOrder && importX.flatConfigs.recommended,
61
+ jsdoc && jsdocPlugin.configs['flat/recommended'],
62
+ prettier && prettierRecommended,
60
63
  ...conditionalPluginList,
61
64
  ].filter(Boolean);
62
65
 
@@ -66,6 +69,7 @@ export const buildConfig = ({
66
69
  const configObject = {
67
70
  files: [...filePatterns],
68
71
  ...(ignores && { ignores }),
72
+ ...(typescript && { plugins: { '@typescript-eslint': tsEslint.plugin } }),
69
73
  languageOptions: {
70
74
  ...commonLanguageOptions,
71
75
  ...(typescript && commonParser),
@@ -74,7 +78,7 @@ export const buildConfig = ({
74
78
  ...(typescript && { parserOptions: { tsconfigRootDir: process.cwd(), ...parserOptions } }),
75
79
  },
76
80
  settings: {
77
- ...(importOrder && { 'import/resolver': { typescript: {} } }),
81
+ ...(importOrder && { 'import-x/resolver': { typescript: {} } }),
78
82
  ...(jsdoc && { jsdoc: { mode: 'typescript' } }),
79
83
  ...extraSettings,
80
84
  ...settings,
@@ -86,5 +90,27 @@ export const buildConfig = ({
86
90
  // Merge user global ignores with common global ignores
87
91
  const mergedGlobalIgnores = Array.isArray(userGlobalIgnores) ? globalIgnores(userGlobalIgnores) : globalIgnores();
88
92
 
89
- return defineConfig([...mergedGlobalIgnores, ...compat.extends(...plugins), configObject]);
93
+ // Collect all flat configs (arrays spread, objects added directly)
94
+ const flatConfigs = [];
95
+
96
+ for (const plugin of plugins) {
97
+ if (Array.isArray(plugin)) {
98
+ flatConfigs.push(...plugin);
99
+ } else if (typeof plugin === 'object' && plugin !== null) {
100
+ flatConfigs.push(plugin);
101
+ }
102
+ }
103
+
104
+ // Wrap plugins with fixupPluginRules for ESLint 10 backward compatibility
105
+ // (addresses removed APIs like context.getFilename in eslint-plugin-react)
106
+ const fixedConfigs = flatConfigs.map((config) => {
107
+ if (!config.plugins) return config;
108
+ const fixed = { ...config, plugins: {} };
109
+ for (const [name, plugin] of Object.entries(config.plugins)) {
110
+ fixed.plugins[name] = fixupPluginRules(plugin);
111
+ }
112
+ return fixed;
113
+ });
114
+
115
+ return defineConfig([...mergedGlobalIgnores, ...fixedConfigs, configObject]);
90
116
  };
@@ -17,14 +17,36 @@ describe('eslint/lib/build-config.js', () => {
17
17
  const module = await import('./build-config.js');
18
18
 
19
19
  // Import dependencies needed for the test.
20
- const { setup } = await import('./setup.js');
21
20
  const { files } = await import('./files.js');
22
- const { compat } = setup();
23
21
 
24
- // Call buildConfig with test parameters (compat, JS-only files, empty options).
25
- const result = module.buildConfig({ compat, files: files.withoutTs, options: {} });
22
+ // Call buildConfig with test parameters (JS-only files, empty options).
23
+ const result = module.buildConfig({ files: files.withoutTs, options: {} });
26
24
 
27
25
  // Verify that the result is an array (ESLint expects configs as an array).
28
26
  expect(Array.isArray(result)).toBe(true);
29
27
  });
28
+
29
+ // Test that buildConfig handles flat config arrays and objects.
30
+ it('should handle flat config arrays and objects', async () => {
31
+ const module = await import('./build-config.js');
32
+ const { files } = await import('./files.js');
33
+
34
+ // A flat config array (simulating eslint-config-next export)
35
+ const flatConfigArray = [{ name: 'test-flat-config', plugins: {}, rules: { 'no-console': 'warn' } }];
36
+
37
+ // A flat config object
38
+ const flatConfigObject = { name: 'test-flat-object', plugins: {}, rules: { 'no-debugger': 'warn' } };
39
+
40
+ const result = module.buildConfig({
41
+ files: files.withTs,
42
+ builtinPlugins: [flatConfigArray, flatConfigObject],
43
+ options: {},
44
+ });
45
+
46
+ expect(Array.isArray(result)).toBe(true);
47
+ // Should contain configs from the flat config array and object
48
+ const configNames = result.filter((c) => c.name).map((c) => c.name);
49
+ expect(configNames).toContain('test-flat-config');
50
+ expect(configNames).toContain('test-flat-object');
51
+ });
30
52
  });
@@ -1,3 +1,2 @@
1
- export { setup } from './setup.js';
2
1
  export { files } from './files.js';
3
2
  export { buildConfig } from './build-config.js';
@@ -2,15 +2,6 @@ import { describe, it, expect } from 'vitest';
2
2
 
3
3
  // Test suite for the ESLint lib module's main entry point.
4
4
  describe('eslint/lib/index.js', () => {
5
- // Test that the module exports the setup function.
6
- it('should export setup function', async () => {
7
- // Dynamically import the index module to test its exports.
8
- const module = await import('./index.js');
9
-
10
- // Verify that setup is a function.
11
- expect(typeof module.setup).toBe('function');
12
- });
13
-
14
5
  // Test that the module exports a files object with TypeScript and non-TypeScript file arrays.
15
6
  it('should export files object', async () => {
16
7
  // Dynamically import the index module to test its exports.
@@ -116,7 +116,7 @@ const prettierRules = (prettier = true) => (prettier ? { 'prettier/prettier': 'w
116
116
  const importOrderRules = (importOrder = true) =>
117
117
  importOrder
118
118
  ? {
119
- 'import/order': [
119
+ 'import-x/order': [
120
120
  'error',
121
121
  {
122
122
  groups: ['builtin', 'external', 'internal', ['parent', 'sibling'], 'index', 'object'],
@@ -43,8 +43,8 @@ describe('eslint/lib/rules.js', () => {
43
43
  // Call commonRules with importOrder option enabled.
44
44
  const result = module.commonRules({ importOrder: true });
45
45
 
46
- // Verify that the import/order rule is present in the config.
47
- expect(result['import/order']).toBeDefined();
46
+ // Verify that the import-x/order rule is present in the config.
47
+ expect(result['import-x/order']).toBeDefined();
48
48
  });
49
49
 
50
50
  // Test that Prettier rules are included when prettier option is true.
@@ -1,26 +1,5 @@
1
- import path from 'node:path';
2
- import { fileURLToPath } from 'node:url';
3
-
4
- import { FlatCompat } from '@eslint/eslintrc';
5
- import js from '@eslint/js';
6
1
  import tsParser from '@typescript-eslint/parser';
7
2
 
8
- const __filename = fileURLToPath(import.meta.url);
9
- const __dirname = path.dirname(__filename);
10
-
11
- /**
12
- * Creates a FlatCompat instance for using flat config format with older
13
- * ESLint configurations.
14
- */
15
- const compat = new FlatCompat({ baseDirectory: __dirname, recommendedConfig: js.configs.recommended });
16
-
17
- /**
18
- * Returns the setup object containing shared utilities for ESLint configs.
19
- *
20
- * @returns {{ compat: FlatCompat, tsParser: typeof tsParser, __dirname: string }} Reusable setup utilities for ESLint configurations.
21
- */
22
- export const setup = () => ({ compat, tsParser, __dirname });
23
-
24
3
  /**
25
4
  * Common parser configuration for TypeScript files.
26
5
  *
@@ -2,15 +2,6 @@ import { describe, it, expect } from 'vitest';
2
2
 
3
3
  // Test suite for the ESLint setup utilities module.
4
4
  describe('eslint/lib/setup.js', () => {
5
- // Test that the module exports the setup function.
6
- it('should export setup function', async () => {
7
- // Dynamically import the setup module to test its exports.
8
- const module = await import('./setup.js');
9
-
10
- // Verify that setup is a function.
11
- expect(typeof module.setup).toBe('function');
12
- });
13
-
14
5
  // Test that the module exports the commonParser object with a parser property.
15
6
  it('should export commonParser object', async () => {
16
7
  // Dynamically import the setup module to test its exports.
@@ -9,9 +9,21 @@
9
9
  * =====================================================================
10
10
  */
11
11
 
12
- import { setup, buildConfig, files } from './lib/index.js';
12
+ import nextCoreWebVitals from 'eslint-config-next/core-web-vitals';
13
13
 
14
- const { compat } = setup();
14
+ import { buildConfig, files } from './lib/index.js';
15
+
16
+ /**
17
+ * Removes the next/typescript item from the core-web-vitals config array.
18
+ * The \@typescript-eslint plugin is registered on the main config object
19
+ * instead (via build-config.js when typescript: true), which avoids plugin
20
+ * redefinition errors when TypeScript rules are applied in the shared config.
21
+ *
22
+ * @param {import('eslint').Linter.Config[]} configs - Config array to process.
23
+ *
24
+ * @returns {import('eslint').Linter.Config[]} Config array with next/typescript removed.
25
+ */
26
+ const prepareNextConfig = (configs) => configs.filter((c) => c.name !== 'next/typescript');
15
27
 
16
28
  /**
17
29
  * Creates an ESLint configuration object for Next.js projects with TypeScript
@@ -38,13 +50,8 @@ export const createConfig = (options = {}) => {
38
50
  const { prettier = true, react = true, a11y = true, importOrder = true, jsdoc = true } = options;
39
51
 
40
52
  return buildConfig({
41
- compat,
42
53
  files: files.withTs,
43
- builtinPlugins: ['next/core-web-vitals', 'next/typescript', 'plugin:@typescript-eslint/recommended'],
44
- conditionalPlugins: {
45
- react: ['plugin:react/recommended', 'plugin:react-hooks/recommended'],
46
- a11y: 'plugin:jsx-a11y/recommended',
47
- },
54
+ builtinPlugins: [...prepareNextConfig(nextCoreWebVitals)],
48
55
  parserOptions: { ecmaFeatures: { jsx: true } },
49
56
  settings: { react: { version: 'detect' } },
50
57
  rules: {
@@ -9,9 +9,12 @@
9
9
  * =====================================================================
10
10
  */
11
11
 
12
- import { setup, buildConfig, files } from './lib/index.js';
12
+ import jsxA11y from 'eslint-plugin-jsx-a11y';
13
+ import reactRecommended from 'eslint-plugin-react/configs/recommended.js';
14
+ import reactHooks from 'eslint-plugin-react-hooks';
15
+ import tsEslint from 'typescript-eslint';
13
16
 
14
- const { compat } = setup();
17
+ import { buildConfig, files } from './lib/index.js';
15
18
 
16
19
  /**
17
20
  * Creates an ESLint configuration object for React projects with TypeScript
@@ -37,14 +40,13 @@ export const createConfig = (options = {}) => {
37
40
  const { prettier = true, a11y = true, importOrder = true, jsdoc = true } = options;
38
41
 
39
42
  return buildConfig({
40
- compat,
41
43
  files: files.withTs,
42
44
  builtinPlugins: [
43
- 'plugin:react/recommended',
44
- 'plugin:react-hooks/recommended',
45
- 'plugin:@typescript-eslint/recommended',
45
+ { ...reactRecommended, files: ['**/*.{jsx,tsx}'] },
46
+ { ...reactHooks.configs.flat.recommended, files: ['**/*.{jsx,tsx}'] },
47
+ ...tsEslint.configs.recommended,
46
48
  ],
47
- conditionalPlugins: { a11y: 'plugin:jsx-a11y/recommended' },
49
+ conditionalPlugins: { a11y: { ...jsxA11y.flatConfigs.recommended, files: ['**/*.{jsx,tsx}'] } },
48
50
  parserOptions: { ecmaFeatures: { jsx: true } },
49
51
  settings: { react: { version: 'detect' } },
50
52
  rules: { 'react/react-in-jsx-scope': 'off', 'react/no-unknown-property': ['error', { ignore: ['jsx', 'global'] }] },
@@ -9,9 +9,9 @@
9
9
  * =====================================================================
10
10
  */
11
11
 
12
- import { setup, buildConfig, files } from './lib/index.js';
12
+ import tsEslint from 'typescript-eslint';
13
13
 
14
- const { compat } = setup();
14
+ import { buildConfig, files } from './lib/index.js';
15
15
 
16
16
  /**
17
17
  * Creates an ESLint configuration object for TypeScript projects.
@@ -35,9 +35,8 @@ export const createConfig = (options = {}) => {
35
35
  const { prettier = true, importOrder = true, jsdoc = true } = options;
36
36
 
37
37
  return buildConfig({
38
- compat,
39
38
  files: files.withTs,
40
- builtinPlugins: ['plugin:@typescript-eslint/recommended'],
39
+ builtinPlugins: [...tsEslint.configs.recommended],
41
40
  typescript: true,
42
41
  options: { ...options, prettier, importOrder, jsdoc },
43
42
  });