@vijayhardaha/dev-config 2.0.1 → 2.0.3

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
@@ -79,7 +79,7 @@ v2 drops FlatCompat and uses native ESLint 10 flat configs throughout.
79
79
 
80
80
  1. Install ESLint 10+: `bun add --dev eslint@10`
81
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`
82
+ 3. Remove unused deps: `@eslint/eslintrc`, `@eslint/js`, `eslint-config-prettier`, `eslint-import-resolver-typescript`
83
83
 
84
84
  ## Quick Start
85
85
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vijayhardaha/dev-config",
3
- "version": "2.0.1",
3
+ "version": "2.0.3",
4
4
  "description": "Reusable development configurations for Next.js + TypeScript projects",
5
5
  "scripts": {
6
6
  "lint": "eslint .",
@@ -36,10 +36,17 @@
36
36
  },
37
37
  "exports": {
38
38
  ".": "./src/index.js",
39
+ "./package.json": "./package.json",
39
40
  "./eslint": "./src/eslint/index.js",
41
+ "./eslint/js": "./src/eslint/index.js",
42
+ "./eslint/base": "./src/eslint/index.js",
43
+ "./eslint/common": "./src/eslint/index.js",
40
44
  "./eslint/ts": "./src/eslint/typescript.js",
45
+ "./eslint/typescript": "./src/eslint/typescript.js",
41
46
  "./eslint/react": "./src/eslint/react.js",
47
+ "./eslint/reactjs": "./src/eslint/react.js",
42
48
  "./eslint/next": "./src/eslint/next.js",
49
+ "./eslint/nextjs": "./src/eslint/next.js",
43
50
  "./prettier": "./src/prettier/index.js",
44
51
  "./commitlint": "./src/commitlint/index.js",
45
52
  "./stylelint": "./src/stylelint/index.js",
@@ -3,7 +3,6 @@ import { defineConfig } from 'eslint/config';
3
3
  import importX from 'eslint-plugin-import-x';
4
4
  import jsdocPlugin from 'eslint-plugin-jsdoc';
5
5
  import prettierRecommended from 'eslint-plugin-prettier/recommended';
6
- import tsEslint from 'typescript-eslint';
7
6
 
8
7
  import { globalIgnores } from './ignores.js';
9
8
  import { commonLanguageOptions } from './language-options.js';
@@ -11,7 +10,7 @@ import { commonRules } from './rules.js';
11
10
  import { commonParser } from './setup.js';
12
11
 
13
12
  /**
14
- * Filters and flattens conditional plugins based on user options.
13
+ * Filters conditional plugins based on user options.
15
14
  *
16
15
  * @param {object} conditionalPlugins - Plugin map keyed by option name.
17
16
  * @param {object} options - User-provided options.
@@ -24,7 +23,7 @@ const getEnabledPlugins = (conditionalPlugins, options) =>
24
23
  .flatMap(([, value]) => (Array.isArray(value) ? value : [value]));
25
24
 
26
25
  /**
27
- * Flattens a mixed list of config arrays and objects into a flat config array.
26
+ * Flattens a mixed list of config arrays and objects.
28
27
  *
29
28
  * @param {(Array|object)[]} plugins - Mixed list of flat config arrays and objects.
30
29
  *
@@ -45,7 +44,7 @@ const flattenPlugins = (plugins) => {
45
44
  };
46
45
 
47
46
  /**
48
- * Wraps plugin rules with fixupPluginRules for ESLint 10 backward compatibility.
47
+ * Wraps plugin rules with fixupPluginRules for backward compatibility.
49
48
  *
50
49
  * @param {object[]} flatConfigs - Flat config array.
51
50
  *
@@ -65,9 +64,61 @@ const fixPlugins = (flatConfigs) =>
65
64
  });
66
65
 
67
66
  /**
68
- * Merges user-provided global ignores with the common defaults.
67
+ * Removes centrally-registered plugins from individual configs to prevent
68
+ * "Cannot redefine plugin" errors.
69
69
  *
70
- * @param {string[]|undefined} userGlobalIgnores - User-provided global ignore patterns.
70
+ * @param {object[]} flatConfigs - Flat config array.
71
+ * @param {string[]} pluginNames - Plugin names to strip from configs.
72
+ *
73
+ * @returns {object[]} Config array with specified plugins removed.
74
+ */
75
+ const stripPlugins = (flatConfigs, pluginNames) => {
76
+ if (pluginNames.length === 0) return flatConfigs;
77
+
78
+ const skip = new Set(pluginNames);
79
+
80
+ return flatConfigs.map((config) => {
81
+ if (!config.plugins) return config;
82
+
83
+ const plugins = { ...config.plugins };
84
+
85
+ for (const name of skip) {
86
+ delete plugins[name];
87
+ }
88
+
89
+ if (Object.keys(plugins).length === 0) {
90
+ const { plugins: _, ...rest } = config;
91
+
92
+ return rest;
93
+ }
94
+
95
+ return { ...config, plugins };
96
+ });
97
+ };
98
+
99
+ /**
100
+ * Removes the parser from individual configs when the main config provides one.
101
+ * Prevents parser conflicts (e.g., eslint-config-next/parser vs `@typescript-eslint/parser`).
102
+ *
103
+ * @param {object[]} flatConfigs - Flat config array.
104
+ *
105
+ * @returns {object[]} Config array with parsers removed.
106
+ */
107
+ const stripParser = (flatConfigs) =>
108
+ flatConfigs.map((config) => {
109
+ if (!config.languageOptions?.parser) return config;
110
+
111
+ const { parser: _, ...languageOptions } = config.languageOptions;
112
+
113
+ return Object.keys(languageOptions).length > 0
114
+ ? { ...config, languageOptions }
115
+ : { ...config, languageOptions: undefined };
116
+ });
117
+
118
+ /**
119
+ * Merges user-provided global ignores with common defaults.
120
+ *
121
+ * @param {string[]|undefined} userGlobalIgnores - User-provided ignore patterns.
71
122
  *
72
123
  * @returns {object} ESLint ignores config object.
73
124
  */
@@ -75,12 +126,14 @@ const mergeGlobalIgnores = (userGlobalIgnores) =>
75
126
  Array.isArray(userGlobalIgnores) ? globalIgnores(userGlobalIgnores) : globalIgnores();
76
127
 
77
128
  /**
78
- * Builds the main ESLint config object with language options, settings, and rules.
129
+ * Builds the main ESLint config object with language options, settings, rules,
130
+ * and centrally-registered plugins.
79
131
  *
80
132
  * @param {object} ctx - Context object with all config parameters.
81
133
  * @param {string[]} ctx.filePatterns - File patterns to apply the config to.
82
134
  * @param {object} ctx.opts - Resolved user options.
83
135
  * @param {boolean} ctx.typescript - Enable TypeScript support.
136
+ * @param {object} ctx.centralPlugins - Plugins to register on the main config.
84
137
  * @param {object} ctx.extraLanguageOptions - Additional language options.
85
138
  * @param {object} ctx.parserOptions - Parser options.
86
139
  * @param {object} ctx.extraSettings - Additional settings.
@@ -92,6 +145,7 @@ const buildConfigObject = ({
92
145
  filePatterns,
93
146
  opts,
94
147
  typescript,
148
+ centralPlugins = {},
95
149
  extraLanguageOptions,
96
150
  parserOptions,
97
151
  extraSettings,
@@ -102,12 +156,13 @@ const buildConfigObject = ({
102
156
  return {
103
157
  files: [...filePatterns],
104
158
  ...(ignores && { ignores }),
105
- ...(typescript && { plugins: { '@typescript-eslint': tsEslint.plugin } }),
159
+ plugins: Object.fromEntries(
160
+ Object.entries(centralPlugins).map(([name, plugin]) => [name, fixupPluginRules(plugin)])
161
+ ),
106
162
  languageOptions: {
107
163
  ...commonLanguageOptions,
108
164
  ...(typescript && commonParser),
109
165
  ...extraLanguageOptions,
110
- ...languageOptions,
111
166
  ...(typescript && { parserOptions: { tsconfigRootDir: process.cwd(), ...parserOptions } }),
112
167
  },
113
168
  settings: {
@@ -126,12 +181,13 @@ const buildConfigObject = ({
126
181
  };
127
182
 
128
183
  /**
129
- * Builds a flat ESLint configuration with support for various options.
184
+ * Builds a flat ESLint configuration.
130
185
  *
131
186
  * @param {object} config - Configuration options.
132
187
  * @param {string[]} config.files - File patterns to apply the config to.
133
188
  * @param {(Array|object)[]} config.builtinPlugins - Flat config arrays or objects to always include.
134
189
  * @param {object} config.conditionalPlugins - Conditional plugins based on options.
190
+ * @param {object} config.centralPlugins - Plugins registered on the main config object.
135
191
  * @param {object} [config.languageOptions] - Additional language options.
136
192
  * @param {object} [config.parserOptions] - Parser options.
137
193
  * @param {object} [config.settings] - Settings object.
@@ -145,6 +201,7 @@ export const buildConfig = ({
145
201
  files: filePatterns,
146
202
  builtinPlugins = [],
147
203
  conditionalPlugins = {},
204
+ centralPlugins = {},
148
205
  languageOptions: extraLanguageOptions = {},
149
206
  parserOptions = {},
150
207
  settings: extraSettings = {},
@@ -166,18 +223,21 @@ export const buildConfig = ({
166
223
  ].filter(Boolean);
167
224
 
168
225
  const flatConfigs = flattenPlugins(mergedPlugins);
169
- const fixedConfigs = fixPlugins(flatConfigs);
226
+ const wrappedConfigs = fixPlugins(flatConfigs);
227
+ const strippedConfigs = stripPlugins(wrappedConfigs, Object.keys(centralPlugins));
228
+ const parsedConfigs = typescript ? stripParser(strippedConfigs) : strippedConfigs;
170
229
  const mergedGlobalIgnores = mergeGlobalIgnores(opts.globalIgnores);
171
230
 
172
231
  const configObject = buildConfigObject({
173
232
  filePatterns,
174
233
  opts,
175
234
  typescript,
235
+ centralPlugins,
176
236
  extraLanguageOptions,
177
237
  parserOptions,
178
238
  extraSettings,
179
239
  extraRules,
180
240
  });
181
241
 
182
- return defineConfig([...mergedGlobalIgnores, ...fixedConfigs, configObject]);
242
+ return defineConfig([...mergedGlobalIgnores, ...parsedConfigs, configObject]);
183
243
  };
@@ -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: {
@@ -10,6 +10,7 @@
10
10
  */
11
11
 
12
12
  import jsxA11y from 'eslint-plugin-jsx-a11y';
13
+ import reactPlugin from 'eslint-plugin-react';
13
14
  import reactRecommended from 'eslint-plugin-react/configs/recommended.js';
14
15
  import reactHooks from 'eslint-plugin-react-hooks';
15
16
  import tsEslint from 'typescript-eslint';
@@ -42,11 +43,12 @@ export const createConfig = (options = {}) => {
42
43
  return buildConfig({
43
44
  files: files.withTs,
44
45
  builtinPlugins: [
45
- { ...reactRecommended, files: ['**/*.{jsx,tsx}'] },
46
- { ...reactHooks.configs.flat.recommended, files: ['**/*.{jsx,tsx}'] },
46
+ { ...reactRecommended, files: files.withTs },
47
+ { ...reactHooks.configs.flat.recommended, files: files.withTs },
47
48
  ...tsEslint.configs.recommended,
48
49
  ],
49
- conditionalPlugins: { a11y: { ...jsxA11y.flatConfigs.recommended, files: ['**/*.{jsx,tsx}'] } },
50
+ centralPlugins: { react: reactPlugin, 'react-hooks': reactHooks, '@typescript-eslint': tsEslint.plugin },
51
+ conditionalPlugins: { a11y: { ...jsxA11y.flatConfigs.recommended, files: files.withTs } },
50
52
  parserOptions: { ecmaFeatures: { jsx: true } },
51
53
  settings: { react: { version: 'detect' } },
52
54
  rules: { 'react/react-in-jsx-scope': 'off', 'react/no-unknown-property': ['error', { ignore: ['jsx', 'global'] }] },
@@ -37,6 +37,7 @@ export const createConfig = (options = {}) => {
37
37
  return buildConfig({
38
38
  files: files.withTs,
39
39
  builtinPlugins: [...tsEslint.configs.recommended],
40
+ centralPlugins: { '@typescript-eslint': tsEslint.plugin },
40
41
  typescript: true,
41
42
  options: { ...options, prettier, importOrder, jsdoc },
42
43
  });