zeno-config 0.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/README.md +271 -0
- package/package.json +89 -0
- package/src/eslint/index.d.ts +124 -0
- package/src/eslint/index.js +373 -0
- package/src/eslint/rules/baseRules.js +753 -0
- package/src/eslint/rules/importPluginRules.js +200 -0
- package/src/eslint/rules/jsxA11yPluginRules.js +195 -0
- package/src/eslint/rules/nodePluginRules.js +128 -0
- package/src/eslint/rules/reactHooksPluginRules.js +27 -0
- package/src/eslint/rules/reactPluginRules.js +476 -0
- package/src/eslint/rules/reactYouMightNotNeedAnEffectPluginRules.js +21 -0
- package/src/eslint/rules/stylisticPluginRules.js +330 -0
- package/src/eslint/rules/typescriptPluginRules.js +533 -0
- package/src/eslint/rules/unicornPluginRules.js +441 -0
- package/src/extensions.d.ts +51 -0
- package/src/extensions.js +49 -0
- package/src/prettier.d.ts +4 -0
- package/src/prettier.js +16 -0
- package/src/tsconfig.base.json +31 -0
- package/src/tsconfig.react.json +13 -0
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
import { defineConfig } from 'eslint/config';
|
|
2
|
+
import js from '@eslint/js';
|
|
3
|
+
import globals from 'globals';
|
|
4
|
+
import importX from 'eslint-plugin-import-x';
|
|
5
|
+
import reactPlugin from 'eslint-plugin-react';
|
|
6
|
+
import reactHooksPlugin from 'eslint-plugin-react-hooks';
|
|
7
|
+
import prettierPlugin from 'eslint-plugin-prettier/recommended';
|
|
8
|
+
import stylisticPlugin from '@stylistic/eslint-plugin';
|
|
9
|
+
import nodePlugin from 'eslint-plugin-n';
|
|
10
|
+
import reactYouMightNotNeedAnEffectPlugin from 'eslint-plugin-react-you-might-not-need-an-effect';
|
|
11
|
+
import jsxA11yPlugin from 'eslint-plugin-jsx-a11y';
|
|
12
|
+
import unicornPlugin from 'eslint-plugin-unicorn';
|
|
13
|
+
import typescriptEslint from 'typescript-eslint';
|
|
14
|
+
import getBaseRules from './rules/baseRules.js';
|
|
15
|
+
import getImportPluginRules from './rules/importPluginRules.js';
|
|
16
|
+
import getReactPluginRules from './rules/reactPluginRules.js';
|
|
17
|
+
import getReactHooksPluginRules from './rules/reactHooksPluginRules.js';
|
|
18
|
+
import getStylisticPluginRules from './rules/stylisticPluginRules.js';
|
|
19
|
+
import getNodePluginRules from './rules/nodePluginRules.js';
|
|
20
|
+
import getReactYouMightNotNeedAnEffectPluginRules from './rules/reactYouMightNotNeedAnEffectPluginRules.js';
|
|
21
|
+
import getJsxA11yPluginRules from './rules/jsxA11yPluginRules.js';
|
|
22
|
+
import getUnicornPluginRules from './rules/unicornPluginRules.js';
|
|
23
|
+
import getTypescriptPluginRules from './rules/typescriptPluginRules.js';
|
|
24
|
+
import {
|
|
25
|
+
allExtensions,
|
|
26
|
+
allExtensionsString,
|
|
27
|
+
nodeExtensions,
|
|
28
|
+
nodeExtensionsString,
|
|
29
|
+
reactJsExtensions,
|
|
30
|
+
reactJsExtensionsString,
|
|
31
|
+
reactJsExtensionsExtended,
|
|
32
|
+
reactJsExtensionsExtendedString,
|
|
33
|
+
reactExtensions,
|
|
34
|
+
reactExtensionsString,
|
|
35
|
+
reactExtensionsExtended,
|
|
36
|
+
reactExtensionsExtendedString,
|
|
37
|
+
typescriptExtensions,
|
|
38
|
+
typescriptExtensionsString,
|
|
39
|
+
} from '../extensions.js';
|
|
40
|
+
|
|
41
|
+
const ignoreDirs = [
|
|
42
|
+
'**/node_modules/*',
|
|
43
|
+
'**/dist/*',
|
|
44
|
+
'**/build/*',
|
|
45
|
+
'**/coverage/*',
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Creates the base ESLint configuration.
|
|
50
|
+
*
|
|
51
|
+
* @param {Object} [options={}] - Configuration options.
|
|
52
|
+
* @param {string[]} [options.ignoreExports] - Export patterns to ignore for import rules.
|
|
53
|
+
* @param {Object} [options.extensionsIgnorePattern] - Extension patterns to ignore for import rules.
|
|
54
|
+
* @param {string} [options.webpackConfig] - Path to webpack config for import resolver.
|
|
55
|
+
* @returns {Array} ESLint flat config array.
|
|
56
|
+
*/
|
|
57
|
+
const baseConfig = (options = {}) => {
|
|
58
|
+
return [
|
|
59
|
+
{
|
|
60
|
+
name: 'zeno/base',
|
|
61
|
+
files: [`**/*{${allExtensionsString}}`],
|
|
62
|
+
ignores: [...ignoreDirs],
|
|
63
|
+
languageOptions: {
|
|
64
|
+
ecmaVersion: 'latest',
|
|
65
|
+
sourceType: 'module',
|
|
66
|
+
globals: {
|
|
67
|
+
...globals.node,
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
settings: {
|
|
71
|
+
'import-x/resolver': {
|
|
72
|
+
node: { extensions: allExtensions },
|
|
73
|
+
...(options.webpackConfig
|
|
74
|
+
? { webpack: { config: options.webpackConfig } }
|
|
75
|
+
: {}),
|
|
76
|
+
},
|
|
77
|
+
},
|
|
78
|
+
plugins: {
|
|
79
|
+
'import-x': importX,
|
|
80
|
+
'@stylistic': stylisticPlugin,
|
|
81
|
+
unicorn: unicornPlugin,
|
|
82
|
+
},
|
|
83
|
+
rules: {
|
|
84
|
+
...getBaseRules(),
|
|
85
|
+
...getImportPluginRules({
|
|
86
|
+
ignoreExports: options.ignoreExports,
|
|
87
|
+
extensionsIgnorePattern: options.extensionsIgnorePattern,
|
|
88
|
+
}),
|
|
89
|
+
...getStylisticPluginRules(),
|
|
90
|
+
...getUnicornPluginRules(),
|
|
91
|
+
},
|
|
92
|
+
extends: [
|
|
93
|
+
// if a new rule is added it'll use the recommended setting until it's added to rules files
|
|
94
|
+
js.configs.recommended,
|
|
95
|
+
],
|
|
96
|
+
},
|
|
97
|
+
];
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Creates the Node.js-specific ESLint configuration.
|
|
102
|
+
*
|
|
103
|
+
* @param {Object} [options={}] - Configuration options.
|
|
104
|
+
* @param {string[]} [options.ignoreDirs] - Additional directories to ignore for Node-specific rules.
|
|
105
|
+
* @returns {Array} ESLint flat config array.
|
|
106
|
+
*/
|
|
107
|
+
const nodeConfig = (options = {}) => {
|
|
108
|
+
let ignores = [...ignoreDirs];
|
|
109
|
+
if (options.ignoreDirs && options.ignoreDirs.length > 0) {
|
|
110
|
+
const optionsIgnoreDirs = options.ignoreDirs.map((dir) => {
|
|
111
|
+
return `${dir}/**/*{${nodeExtensionsString}}`;
|
|
112
|
+
});
|
|
113
|
+
ignores = [...ignores, ...optionsIgnoreDirs];
|
|
114
|
+
}
|
|
115
|
+
return [
|
|
116
|
+
{
|
|
117
|
+
name: 'zeno/node',
|
|
118
|
+
files: [`**/*{${nodeExtensionsString}}`],
|
|
119
|
+
ignores,
|
|
120
|
+
languageOptions: {
|
|
121
|
+
ecmaVersion: 'latest',
|
|
122
|
+
sourceType: 'module',
|
|
123
|
+
globals: {
|
|
124
|
+
...globals.node,
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
plugins: {
|
|
128
|
+
n: nodePlugin,
|
|
129
|
+
},
|
|
130
|
+
rules: { ...getNodePluginRules() },
|
|
131
|
+
},
|
|
132
|
+
];
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Creates the React-specific ESLint configuration.
|
|
137
|
+
*
|
|
138
|
+
* @param {Object} [options={}] - Configuration options.
|
|
139
|
+
* @param {string[]} [options.reactDirs] - Directories containing React files (for projects using .js for both React and Node).
|
|
140
|
+
* @param {Object} [options.extensionsIgnorePattern] - Extension patterns to ignore for import rules.
|
|
141
|
+
* @returns {Array} ESLint flat config array.
|
|
142
|
+
*/
|
|
143
|
+
const reactConfig = (options = {}) => {
|
|
144
|
+
let files = [`**/*{${reactExtensionsString}}`];
|
|
145
|
+
let extensions = reactExtensions;
|
|
146
|
+
|
|
147
|
+
if (
|
|
148
|
+
options.reactDirs &&
|
|
149
|
+
Array.isArray(options.reactDirs) &&
|
|
150
|
+
options.reactDirs.length > 0
|
|
151
|
+
) {
|
|
152
|
+
files = options.reactDirs.map((dir) => {
|
|
153
|
+
return `${dir}/**/*{${reactExtensionsExtendedString}}`;
|
|
154
|
+
});
|
|
155
|
+
extensions = reactExtensionsExtended;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return [
|
|
159
|
+
{
|
|
160
|
+
name: 'zeno/react',
|
|
161
|
+
files,
|
|
162
|
+
ignores: [...ignoreDirs],
|
|
163
|
+
languageOptions: {
|
|
164
|
+
globals: {
|
|
165
|
+
...globals.browser,
|
|
166
|
+
},
|
|
167
|
+
parserOptions: {
|
|
168
|
+
ecmaFeatures: {
|
|
169
|
+
jsx: true,
|
|
170
|
+
},
|
|
171
|
+
},
|
|
172
|
+
},
|
|
173
|
+
settings: {
|
|
174
|
+
react: {
|
|
175
|
+
version: 'detect',
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
rules: {
|
|
179
|
+
...getReactPluginRules({ extensions }),
|
|
180
|
+
...getReactHooksPluginRules(),
|
|
181
|
+
...getReactYouMightNotNeedAnEffectPluginRules(),
|
|
182
|
+
...getJsxA11yPluginRules(),
|
|
183
|
+
|
|
184
|
+
'import-x/extensions': [
|
|
185
|
+
'error',
|
|
186
|
+
'ignorePackages',
|
|
187
|
+
{
|
|
188
|
+
js: 'never',
|
|
189
|
+
jsx: 'never',
|
|
190
|
+
ts: 'never',
|
|
191
|
+
tsx: 'never',
|
|
192
|
+
...options.extensionsIgnorePattern,
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
},
|
|
196
|
+
extends: [
|
|
197
|
+
// if a new rule is added it'll use the recommended setting until it's added to the rules files
|
|
198
|
+
reactPlugin.configs.flat.recommended,
|
|
199
|
+
reactPlugin.configs.flat['jsx-runtime'],
|
|
200
|
+
reactHooksPlugin.configs.flat.recommended,
|
|
201
|
+
reactYouMightNotNeedAnEffectPlugin.configs.recommended,
|
|
202
|
+
jsxA11yPlugin.flatConfigs.recommended,
|
|
203
|
+
],
|
|
204
|
+
},
|
|
205
|
+
];
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Creates the TypeScript-specific ESLint configuration.
|
|
210
|
+
*
|
|
211
|
+
* @returns {Array} ESLint flat config array.
|
|
212
|
+
*/
|
|
213
|
+
const typescriptConfig = () => {
|
|
214
|
+
return [
|
|
215
|
+
{
|
|
216
|
+
name: 'zeno/typescript',
|
|
217
|
+
files: [`**/*{${typescriptExtensionsString}}`],
|
|
218
|
+
languageOptions: {
|
|
219
|
+
parser: typescriptEslint.parser,
|
|
220
|
+
// parserOptions: {
|
|
221
|
+
// projectService: true,
|
|
222
|
+
// },
|
|
223
|
+
},
|
|
224
|
+
plugins: {
|
|
225
|
+
'@typescript-eslint': typescriptEslint.plugin,
|
|
226
|
+
},
|
|
227
|
+
rules: {
|
|
228
|
+
...getTypescriptPluginRules(),
|
|
229
|
+
|
|
230
|
+
// other rules the ts compiler handles
|
|
231
|
+
'react/prop-types': 'off',
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
];
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const configs = {
|
|
238
|
+
getBase: baseConfig,
|
|
239
|
+
getReact: reactConfig,
|
|
240
|
+
getNode: nodeConfig,
|
|
241
|
+
getTypescript: typescriptConfig,
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
const internals = {
|
|
245
|
+
configs,
|
|
246
|
+
extensions: {
|
|
247
|
+
allExtensions,
|
|
248
|
+
allExtensionsString,
|
|
249
|
+
nodeExtensions,
|
|
250
|
+
nodeExtensionsString,
|
|
251
|
+
reactJsExtensions,
|
|
252
|
+
reactJsExtensionsString,
|
|
253
|
+
reactJsExtensionsExtended,
|
|
254
|
+
reactJsExtensionsExtendedString,
|
|
255
|
+
reactExtensions,
|
|
256
|
+
reactExtensionsString,
|
|
257
|
+
reactExtensionsExtended,
|
|
258
|
+
reactExtensionsExtendedString,
|
|
259
|
+
typescriptExtensions,
|
|
260
|
+
typescriptExtensionsString,
|
|
261
|
+
},
|
|
262
|
+
rules: {
|
|
263
|
+
getBaseRules,
|
|
264
|
+
getImportPluginRules,
|
|
265
|
+
getStylisticPluginRules,
|
|
266
|
+
getUnicornPluginRules,
|
|
267
|
+
getReactPluginRules,
|
|
268
|
+
getReactHooksPluginRules,
|
|
269
|
+
getReactYouMightNotNeedAnEffectPluginRules,
|
|
270
|
+
getJsxA11yPluginRules,
|
|
271
|
+
},
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
// TODO: make sure to add a suggestion to set the engines fields in package.json
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Defines a Zeno ESLint configuration.
|
|
278
|
+
*
|
|
279
|
+
* @param {Object|Array} arg1 - Options object or additional config array. If an array, treated as additional config.
|
|
280
|
+
* @param {boolean} [arg1.react=false] - Enable React-specific rules.
|
|
281
|
+
* @param {boolean} [arg1.ts=true] - Enable TypeScript-specific rules.
|
|
282
|
+
* @param {string[]} [arg1.reactDirs=[]] - Directories containing React files (for projects using .js for both React and Node).
|
|
283
|
+
* @param {string[]} [arg1.nodeIgnoreDirs=[]] - Directories to ignore for Node-specific rules.
|
|
284
|
+
* @param {string[]} [arg1.ignoreExports=[]] - Export patterns to ignore for import rules.
|
|
285
|
+
* @param {Object} [arg1.extensionsIgnorePattern={}] - Extension patterns to ignore for import rules.
|
|
286
|
+
* @param {string} [arg1.webpackConfig] - Path to webpack config for import resolver.
|
|
287
|
+
* @param {Array} [arg2] - Additional ESLint config objects to merge (only used if arg1 is options object).
|
|
288
|
+
* @returns {Array} ESLint flat config array.
|
|
289
|
+
*
|
|
290
|
+
* @example
|
|
291
|
+
* // With options object
|
|
292
|
+
* defineZenoConfig({ react: true, ts: true })
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* // With additional config
|
|
296
|
+
* defineZenoConfig({ react: true }, [customConfig])
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* // With config array only
|
|
300
|
+
* defineZenoConfig([customConfig])
|
|
301
|
+
*/
|
|
302
|
+
const defineZenoConfig = (arg1, arg2) => {
|
|
303
|
+
let options = {
|
|
304
|
+
react: false,
|
|
305
|
+
ts: false,
|
|
306
|
+
|
|
307
|
+
// if a project uses .js file extension for both react and node files this will help separate the rules for each
|
|
308
|
+
reactDirs: [],
|
|
309
|
+
nodeIgnoreDirs: [],
|
|
310
|
+
|
|
311
|
+
ignoreExports: [],
|
|
312
|
+
extensionsIgnorePattern: {},
|
|
313
|
+
webpackConfig: undefined,
|
|
314
|
+
};
|
|
315
|
+
let config;
|
|
316
|
+
|
|
317
|
+
if (Array.isArray(arg1)) {
|
|
318
|
+
config = arg1;
|
|
319
|
+
} else {
|
|
320
|
+
options = arg1 ? { ...options, ...arg1 } : options;
|
|
321
|
+
config = arg2 || [];
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Ensure array options are arrays
|
|
325
|
+
if (!Array.isArray(options.reactDirs)) {
|
|
326
|
+
options.reactDirs = [];
|
|
327
|
+
}
|
|
328
|
+
if (!Array.isArray(options.nodeIgnoreDirs)) {
|
|
329
|
+
options.nodeIgnoreDirs = [];
|
|
330
|
+
}
|
|
331
|
+
if (!Array.isArray(options.ignoreExports)) {
|
|
332
|
+
options.ignoreExports = [];
|
|
333
|
+
}
|
|
334
|
+
if (
|
|
335
|
+
typeof options.extensionsIgnorePattern !== 'object' ||
|
|
336
|
+
options.extensionsIgnorePattern === null
|
|
337
|
+
) {
|
|
338
|
+
options.extensionsIgnorePattern = {};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// use the reactDirs as the nodeIgnoreDirs if they are not set since they would likely be the same
|
|
342
|
+
if (
|
|
343
|
+
options.react &&
|
|
344
|
+
options.reactDirs.length > 0 &&
|
|
345
|
+
options.nodeIgnoreDirs.length === 0
|
|
346
|
+
) {
|
|
347
|
+
options.nodeIgnoreDirs = [...options.reactDirs];
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
return defineConfig([
|
|
351
|
+
...configs.getBase({
|
|
352
|
+
ignoreExports: options.ignoreExports,
|
|
353
|
+
webpackConfig: options.webpackConfig,
|
|
354
|
+
extensionsIgnorePattern: options.extensionsIgnorePattern,
|
|
355
|
+
}),
|
|
356
|
+
...configs.getNode({ ignoreDirs: options.nodeIgnoreDirs }),
|
|
357
|
+
...(options.react
|
|
358
|
+
? configs.getReact({
|
|
359
|
+
reactDirs: options.reactDirs,
|
|
360
|
+
extensionsIgnorePattern: options.extensionsIgnorePattern,
|
|
361
|
+
})
|
|
362
|
+
: []),
|
|
363
|
+
...(options.ts ? configs.getTypescript() : []),
|
|
364
|
+
|
|
365
|
+
...(config || []),
|
|
366
|
+
|
|
367
|
+
// Turn off formatting rules that might conflict with Prettier
|
|
368
|
+
prettierPlugin,
|
|
369
|
+
]);
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
export default internals;
|
|
373
|
+
export { defineZenoConfig };
|