@vijayhardaha/dev-config 2.0.2 → 2.0.4

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,7 +6,7 @@
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.
9
+ > **v2.0.4** — Requires ESLint >=10. Native flat config only. No FlatCompat.
10
10
 
11
11
  ## Features
12
12
 
@@ -21,17 +21,25 @@ Reusable development configuration package for Next.js + TypeScript projects.
21
21
  ## Installation
22
22
 
23
23
  ```bash
24
- bun install @vijayhardaha/dev-config --dev
24
+ bun add --dev @vijayhardaha/dev-config
25
25
  ```
26
26
 
27
27
  ### Install Required Packages
28
28
 
29
29
  ```bash
30
- bun add --dev eslint @eslint/compat 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
30
+ bun add --dev eslint @eslint/compat eslint-config-prettier prettier @prettier/plugin-xml eslint-plugin-prettier globals eslint-plugin-jsdoc eslint-plugin-import-x @typescript-eslint/eslint-plugin @typescript-eslint/parser typescript typescript-eslint husky
31
31
  ```
32
32
 
33
33
  ### Install Optional Packages
34
34
 
35
+ Only install what you need based on your project setup.
36
+
37
+ #### TypeScript Import Resolution
38
+
39
+ ```bash
40
+ bun add --dev eslint-import-resolver-typescript
41
+ ```
42
+
35
43
  #### Stylelint
36
44
 
37
45
  ```bash
@@ -53,7 +61,7 @@ bun add --dev @next/eslint-plugin-next eslint-config-next
53
61
  #### Commitlint
54
62
 
55
63
  ```bash
56
- bun add --dev husky @commitlint/cli @commitlint/config-conventional @commitlint/types
64
+ bun add --dev @commitlint/cli @commitlint/config-conventional @commitlint/types
57
65
  ```
58
66
 
59
67
  #### Next Sitemap
@@ -79,7 +87,14 @@ v2 drops FlatCompat and uses native ESLint 10 flat configs throughout.
79
87
 
80
88
  1. Install ESLint 10+: `bun add --dev eslint@10`
81
89
  2. Replace `eslint-plugin-import` with `eslint-plugin-import-x`
82
- 3. Remove unused deps: `@eslint/eslintrc`, `@eslint/js`, `eslint-config-prettier`, `eslint-import-resolver-typescript`
90
+ 3. Remove unused deps: `@eslint/eslintrc`, `@eslint/js`
91
+
92
+ ### What's new in v2.0.4
93
+
94
+ - **`eslint-config-prettier` restored** — added back to peer deps (required by `eslint-plugin-prettier/recommended`)
95
+ - **`eslint-import-resolver-typescript` restored** — added back as optional peer for TypeScript import resolution
96
+ - **All packages declared as peer deps** — every config module's dependencies are declared with proper `peerDependenciesMeta`
97
+ - **Flat config resolver fix** — switched from string-based `import-x/resolver` to `import-x/resolver-next` with `createTypeScriptImportResolver` for ESLint 10 compatibility
83
98
 
84
99
  ## Quick Start
85
100
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vijayhardaha/dev-config",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "Reusable development configurations for Next.js + TypeScript projects",
5
5
  "scripts": {
6
6
  "lint": "eslint .",
@@ -68,32 +68,55 @@
68
68
  "@commitlint/cli": "^21.0.2",
69
69
  "@commitlint/config-conventional": "^21.0.2",
70
70
  "@commitlint/types": "^21.0.1",
71
- "@vitest/coverage-v8": "^4.1.7",
72
- "eslint-config-next": "^16.2.6",
71
+ "@typescript-eslint/parser": "^8.60.1",
72
+ "@typescript-eslint/eslint-plugin": "^8.60.1",
73
+ "@vitest/coverage-v8": "^4.1.8",
74
+ "eslint": "^10.4.1",
75
+ "eslint-config-next": "^16.2.7",
76
+ "eslint-config-prettier": "^10.1.8",
77
+ "eslint-plugin-import-x": "^4.16.2",
78
+ "eslint-plugin-jsdoc": "^63.0.1",
73
79
  "eslint-plugin-jsx-a11y": "^6.10.2",
80
+ "eslint-plugin-prettier": "^5.5.6",
74
81
  "eslint-plugin-react": "^7.37.5",
75
82
  "eslint-plugin-react-hooks": "^7.1.1",
76
- "next-sitemap": "^4.2.3",
77
- "release-it": "^20.0.1",
78
- "stylelint": "^17.12.0",
79
- "stylelint-config-property-sort-order-smacss": "^11.2.0",
80
- "stylelint-config-standard-scss": "^17.0.0",
81
- "stylelint-order": "^8.1.1",
82
- "vitest": "^4.1.7"
83
+ "globals": "^17.6.0",
84
+ "husky": "^9.1.7",
85
+ "prettier": "^3.8.3",
86
+ "@prettier/plugin-xml": "^3.4.2",
87
+ "release-it": "^20.2.0",
88
+ "typescript": "^6.0.3",
89
+ "typescript-eslint": "^8.60.1",
90
+ "vitest": "^4.1.8"
83
91
  },
84
92
  "peerDependencies": {
93
+ "@commitlint/cli": ">=21",
94
+ "@commitlint/config-conventional": ">=21",
95
+ "@commitlint/types": ">=21",
85
96
  "@eslint/compat": ">=2",
97
+ "@next/eslint-plugin-next": ">=16",
86
98
  "@prettier/plugin-xml": ">=3",
87
99
  "@typescript-eslint/eslint-plugin": ">=8",
88
100
  "@typescript-eslint/parser": ">=8",
89
101
  "eslint": ">=10",
102
+ "eslint-config-next": ">=16",
103
+ "eslint-config-prettier": ">=10",
104
+ "eslint-import-resolver-typescript": ">=4",
90
105
  "eslint-plugin-import-x": ">=4",
91
106
  "eslint-plugin-jsdoc": ">=62",
107
+ "eslint-plugin-jsx-a11y": ">=6",
92
108
  "eslint-plugin-prettier": ">=5",
109
+ "eslint-plugin-react": ">=7",
110
+ "eslint-plugin-react-hooks": ">=5",
93
111
  "globals": ">=17",
94
112
  "husky": ">=9",
95
- "prettier": "^3.8.3",
96
- "typescript": ">=6",
113
+ "next-sitemap": ">=4",
114
+ "prettier": ">=3",
115
+ "stylelint": ">=17",
116
+ "stylelint-config-property-sort-order-smacss": ">=11",
117
+ "stylelint-config-standard-scss": ">=17",
118
+ "stylelint-order": ">=8",
119
+ "typescript": ">=5",
97
120
  "typescript-eslint": ">=8"
98
121
  },
99
122
  "peerDependenciesMeta": {
@@ -109,9 +132,18 @@
109
132
  "@next/eslint-plugin-next": {
110
133
  "optional": true
111
134
  },
135
+ "@typescript-eslint/eslint-plugin": {
136
+ "optional": true
137
+ },
138
+ "@typescript-eslint/parser": {
139
+ "optional": true
140
+ },
112
141
  "eslint-config-next": {
113
142
  "optional": true
114
143
  },
144
+ "eslint-import-resolver-typescript": {
145
+ "optional": true
146
+ },
115
147
  "eslint-plugin-jsx-a11y": {
116
148
  "optional": true
117
149
  },
@@ -121,6 +153,9 @@
121
153
  "eslint-plugin-react-hooks": {
122
154
  "optional": true
123
155
  },
156
+ "husky": {
157
+ "optional": true
158
+ },
124
159
  "next-sitemap": {
125
160
  "optional": true
126
161
  },
@@ -135,12 +170,19 @@
135
170
  },
136
171
  "stylelint-order": {
137
172
  "optional": true
173
+ },
174
+ "typescript": {
175
+ "optional": true
176
+ },
177
+ "typescript-eslint": {
178
+ "optional": true
138
179
  }
139
180
  },
140
181
  "overrides": {
141
182
  "undici": "^7.0.0"
142
183
  },
143
184
  "trustedDependencies": [
185
+ "sharp",
144
186
  "unrs-resolver"
145
187
  ]
146
188
  }
@@ -1,12 +1,20 @@
1
1
  import { fixupPluginRules } from '@eslint/compat';
2
2
  import { defineConfig } from 'eslint/config';
3
- import importX from 'eslint-plugin-import-x';
3
+ import { createNodeResolver, flatConfigs as importXFlatConfigs } from 'eslint-plugin-import-x';
4
4
  import jsdocPlugin from 'eslint-plugin-jsdoc';
5
5
  import prettierRecommended from 'eslint-plugin-prettier/recommended';
6
6
 
7
7
  import { globalIgnores } from './ignores.js';
8
8
  import { commonLanguageOptions } from './language-options.js';
9
9
  import { commonRules } from './rules.js';
10
+ import { commonParser } from './setup.js';
11
+
12
+ let createTypeScriptImportResolver;
13
+ try {
14
+ createTypeScriptImportResolver = (await import('eslint-import-resolver-typescript')).createTypeScriptImportResolver;
15
+ } catch {
16
+ createTypeScriptImportResolver = null;
17
+ }
10
18
 
11
19
  /**
12
20
  * Filters conditional plugins based on user options.
@@ -95,6 +103,25 @@ const stripPlugins = (flatConfigs, pluginNames) => {
95
103
  });
96
104
  };
97
105
 
106
+ /**
107
+ * Removes the parser from individual configs when the main config provides one.
108
+ * Prevents parser conflicts (e.g., eslint-config-next/parser vs `@typescript-eslint/parser`).
109
+ *
110
+ * @param {object[]} flatConfigs - Flat config array.
111
+ *
112
+ * @returns {object[]} Config array with parsers removed.
113
+ */
114
+ const stripParser = (flatConfigs) =>
115
+ flatConfigs.map((config) => {
116
+ if (!config.languageOptions?.parser) return config;
117
+
118
+ const { parser: _, ...languageOptions } = config.languageOptions;
119
+
120
+ return Object.keys(languageOptions).length > 0
121
+ ? { ...config, languageOptions }
122
+ : { ...config, languageOptions: undefined };
123
+ });
124
+
98
125
  /**
99
126
  * Merges user-provided global ignores with common defaults.
100
127
  *
@@ -141,11 +168,17 @@ const buildConfigObject = ({
141
168
  ),
142
169
  languageOptions: {
143
170
  ...commonLanguageOptions,
171
+ ...(typescript && commonParser),
144
172
  ...extraLanguageOptions,
145
173
  ...(typescript && { parserOptions: { tsconfigRootDir: process.cwd(), ...parserOptions } }),
146
174
  },
147
175
  settings: {
148
- ...(opts.importOrder && { 'import-x/resolver': { typescript: {} } }),
176
+ ...(opts.importOrder && {
177
+ 'import-x/resolver-next': [
178
+ createNodeResolver(),
179
+ ...(createTypeScriptImportResolver ? [createTypeScriptImportResolver()] : []),
180
+ ],
181
+ }),
149
182
  ...(opts.jsdoc && { jsdoc: { mode: 'typescript' } }),
150
183
  ...extraSettings,
151
184
  ...settings,
@@ -194,7 +227,7 @@ export const buildConfig = ({
194
227
 
195
228
  const mergedPlugins = [
196
229
  ...builtinPlugins,
197
- opts.importOrder && importX.flatConfigs.recommended,
230
+ opts.importOrder && importXFlatConfigs.recommended,
198
231
  opts.jsdoc && jsdocPlugin.configs['flat/recommended'],
199
232
  opts.prettier && prettierRecommended,
200
233
  ...conditionalPluginList,
@@ -204,6 +237,7 @@ export const buildConfig = ({
204
237
  const flatConfigs = flattenPlugins(mergedPlugins);
205
238
  const wrappedConfigs = fixPlugins(flatConfigs);
206
239
  const strippedConfigs = stripPlugins(wrappedConfigs, Object.keys(centralPlugins));
240
+ const parsedConfigs = typescript ? stripParser(strippedConfigs) : strippedConfigs;
207
241
  const mergedGlobalIgnores = mergeGlobalIgnores(opts.globalIgnores);
208
242
 
209
243
  const configObject = buildConfigObject({
@@ -217,5 +251,5 @@ export const buildConfig = ({
217
251
  extraRules,
218
252
  });
219
253
 
220
- return defineConfig([...mergedGlobalIgnores, ...strippedConfigs, configObject]);
254
+ return defineConfig([...mergedGlobalIgnores, ...parsedConfigs, configObject]);
221
255
  };
@@ -49,4 +49,32 @@ describe('eslint/lib/build-config.js', () => {
49
49
  expect(configNames).toContain('test-flat-config');
50
50
  expect(configNames).toContain('test-flat-object');
51
51
  });
52
+
53
+ // Test that buildConfig sets import-x/resolver-next when importOrder is enabled.
54
+ it('should configure import-x/resolver-next with node resolver when importOrder is enabled', async () => {
55
+ const module = await import('./build-config.js');
56
+ const { files } = await import('./files.js');
57
+
58
+ const result = module.buildConfig({ files: files.withoutTs, options: { importOrder: true } });
59
+
60
+ // The last config object in the array should have the resolver settings
61
+ const configObject = result[result.length - 1];
62
+ expect(configObject.settings).toBeDefined();
63
+ expect(configObject.settings['import-x/resolver-next']).toBeDefined();
64
+ expect(Array.isArray(configObject.settings['import-x/resolver-next'])).toBe(true);
65
+ // Should at least have the node resolver
66
+ expect(configObject.settings['import-x/resolver-next'].length).toBeGreaterThanOrEqual(1);
67
+ });
68
+
69
+ // Test that buildConfig omits import-x/resolver-next when importOrder is disabled.
70
+ it('should omit import-x/resolver-next when importOrder is disabled', async () => {
71
+ const module = await import('./build-config.js');
72
+ const { files } = await import('./files.js');
73
+
74
+ const result = module.buildConfig({ files: files.withoutTs, options: { importOrder: false } });
75
+
76
+ const configObject = result[result.length - 1];
77
+ expect(configObject.settings).toBeDefined();
78
+ expect(configObject.settings['import-x/resolver-next']).toBeUndefined();
79
+ });
52
80
  });
@@ -10,14 +10,18 @@
10
10
  */
11
11
 
12
12
  import nextCoreWebVitals from 'eslint-config-next/core-web-vitals';
13
+ import reactPlugin from 'eslint-plugin-react';
14
+ import reactHooks from 'eslint-plugin-react-hooks';
15
+ import tsEslint from 'typescript-eslint';
13
16
 
14
17
  import { buildConfig, files } from './lib/index.js';
15
18
 
16
19
  /**
17
20
  * Removes the next/typescript item from the core-web-vitals config array.
18
21
  * 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.
22
+ * via centralPlugins, which avoids plugin redefinition errors. The
23
+ * next/typescript config is also removed to prevent parser conflicts with
24
+ * the centrally-managed TypeScript setup.
21
25
  *
22
26
  * @param {import('eslint').Linter.Config[]} configs - Config array to process.
23
27
  *
@@ -52,6 +56,7 @@ export const createConfig = (options = {}) => {
52
56
  return buildConfig({
53
57
  files: files.withTs,
54
58
  builtinPlugins: [...prepareNextConfig(nextCoreWebVitals)],
59
+ centralPlugins: { react: reactPlugin, 'react-hooks': reactHooks, '@typescript-eslint': tsEslint.plugin },
55
60
  parserOptions: { ecmaFeatures: { jsx: true } },
56
61
  settings: { react: { version: 'detect' } },
57
62
  rules: {