zeno-config 1.0.1 → 1.0.2

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
@@ -44,6 +44,7 @@ Create an `eslint.config.js` file in your project root:
44
44
  ```javascript
45
45
  import { defineZenoConfig } from 'zeno-config/eslint';
46
46
 
47
+ // defineZenoConfig returns a Promise - ESLint 9+ flat config supports this natively
47
48
  export default defineZenoConfig({
48
49
  ts: true, // Enable TypeScript support (default: false)
49
50
  react: true, // Enable React support (default: false)
@@ -64,13 +65,13 @@ This is a workaround for a [known limitation](https://github.com/import-js/eslin
64
65
 
65
66
  Add an `engines` field to your `package.json` with your supported Node.js versions. Some rules for Node.js use this:
66
67
 
67
- ```json
68
- {
69
- "engines": {
70
- "node": ">=20"
71
- }
72
- }
73
- ```
68
+ ```json
69
+ {
70
+ "engines": {
71
+ "node": ">=20"
72
+ }
73
+ }
74
+ ```
74
75
 
75
76
  #### Advanced Configuration
76
77
 
@@ -213,13 +214,14 @@ import zenoInternals from 'zeno-config/eslint';
213
214
 
214
215
  const { configs, rules, extensions } = zenoInternals;
215
216
 
216
- export default [
217
+ // Note: getReact() and getTypescript() are async (return Promises)
218
+ export default (async () => [
217
219
  ...configs.getBase(),
218
220
  ...configs.getNode(),
219
- ...configs.getReact(),
220
- ...configs.getTypescript(),
221
+ ...(await configs.getReact()),
222
+ ...(await configs.getTypescript()),
221
223
  // Your custom configs
222
- ];
224
+ ])();
223
225
  ```
224
226
 
225
227
  ### Accessing Individual Rules
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zeno-config",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Preconfigured and opinionated ESLint, Prettier, and TypeScript setup",
5
5
  "author": "Rick Brenn <brenn.rick@gmail.com>",
6
6
  "license": "MIT",
@@ -57,9 +57,9 @@ interface Extensions {
57
57
 
58
58
  interface Configs {
59
59
  getBase: (options?: BaseConfigOptions) => Linter.Config[];
60
- getReact: (options?: ReactConfigOptions) => Linter.Config[];
60
+ getReact: (options?: ReactConfigOptions) => Promise<Linter.Config[]>;
61
61
  getNode: (options?: NodeConfigOptions) => Linter.Config[];
62
- getTypescript: () => Linter.Config[];
62
+ getTypescript: () => Promise<Linter.Config[]>;
63
63
  }
64
64
 
65
65
  interface Rules {
@@ -89,26 +89,29 @@ declare const internals: Internals;
89
89
  /**
90
90
  * Defines a Zeno ESLint configuration.
91
91
  *
92
+ * This function is async because React and TypeScript dependencies are loaded
93
+ * dynamically (only when enabled) to avoid errors when optional deps aren't installed.
94
+ *
92
95
  * @param arg1 - Options object or additional config array. If an array, treated as additional config.
93
96
  * @param arg2 - Additional ESLint config objects to merge (only used if arg1 is options object).
94
- * @returns ESLint flat config array.
97
+ * @returns Promise that resolves to ESLint flat config array.
95
98
  *
96
99
  * @example
97
- * // With options object
98
- * defineZenoConfig({ react: true, ts: true })
100
+ * // With options object (using default export)
101
+ * export default defineZenoConfig({ react: true, ts: true })
99
102
  *
100
103
  * @example
101
104
  * // With additional config
102
- * defineZenoConfig({ react: true }, [customConfig])
105
+ * export default defineZenoConfig({ react: true }, [customConfig])
103
106
  *
104
107
  * @example
105
108
  * // With config array only
106
- * defineZenoConfig([customConfig])
109
+ * export default defineZenoConfig([customConfig])
107
110
  */
108
111
  declare function defineZenoConfig(
109
112
  arg1?: DefineZenoConfigOptions | Linter.Config[],
110
113
  arg2?: Linter.Config[]
111
- ): Linter.Config[];
114
+ ): Promise<Linter.Config[]>;
112
115
 
113
116
  export {
114
117
  type BaseConfigOptions,
@@ -2,15 +2,10 @@ import { defineConfig } from 'eslint/config';
2
2
  import js from '@eslint/js';
3
3
  import globals from 'globals';
4
4
  import importX from 'eslint-plugin-import-x';
5
- import reactPlugin from 'eslint-plugin-react';
6
- import reactHooksPlugin from 'eslint-plugin-react-hooks';
7
5
  import prettierPlugin from 'eslint-plugin-prettier/recommended';
8
6
  import stylisticPlugin from '@stylistic/eslint-plugin';
9
7
  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
8
  import unicornPlugin from 'eslint-plugin-unicorn';
13
- import typescriptEslint from 'typescript-eslint';
14
9
  import getBaseRules from './rules/baseRules.js';
15
10
  import getImportPluginRules from './rules/importPluginRules.js';
16
11
  import getReactPluginRules from './rules/reactPluginRules.js';
@@ -138,9 +133,22 @@ const nodeConfig = (options = {}) => {
138
133
  * @param {Object} [options={}] - Configuration options.
139
134
  * @param {string[]} [options.reactDirs] - Directories containing React files (for projects using .js for both React and Node).
140
135
  * @param {Object} [options.extensionsIgnorePattern] - Extension patterns to ignore for import rules.
141
- * @returns {Array} ESLint flat config array.
136
+ * @returns {Promise<Array>} ESLint flat config array.
142
137
  */
143
- const reactConfig = (options = {}) => {
138
+ const reactConfig = async (options = {}) => {
139
+ // Dynamically import optional React dependencies
140
+ const [
141
+ { default: reactPlugin },
142
+ { default: reactHooksPlugin },
143
+ { default: jsxA11yPlugin },
144
+ { default: reactYouMightNotNeedAnEffectPlugin },
145
+ ] = await Promise.all([
146
+ import('eslint-plugin-react'),
147
+ import('eslint-plugin-react-hooks'),
148
+ import('eslint-plugin-jsx-a11y'),
149
+ import('eslint-plugin-react-you-might-not-need-an-effect'),
150
+ ]);
151
+
144
152
  let files = [`**/*{${reactExtensionsString}}`];
145
153
  let extensions = reactExtensions;
146
154
 
@@ -208,9 +216,12 @@ const reactConfig = (options = {}) => {
208
216
  /**
209
217
  * Creates the TypeScript-specific ESLint configuration.
210
218
  *
211
- * @returns {Array} ESLint flat config array.
219
+ * @returns {Promise<Array>} ESLint flat config array.
212
220
  */
213
- const typescriptConfig = () => {
221
+ const typescriptConfig = async () => {
222
+ // Dynamically import optional TypeScript dependencies
223
+ const { default: typescriptEslint } = await import('typescript-eslint');
224
+
214
225
  return [
215
226
  {
216
227
  name: 'zeno/typescript',
@@ -285,7 +296,7 @@ const internals = {
285
296
  * @param {Object} [arg1.extensionsIgnorePattern={}] - Extension patterns to ignore for import rules.
286
297
  * @param {string} [arg1.webpackConfig] - Path to webpack config for import resolver.
287
298
  * @param {Array} [arg2] - Additional ESLint config objects to merge (only used if arg1 is options object).
288
- * @returns {Array} ESLint flat config array.
299
+ * @returns {Promise<Array>} ESLint flat config array.
289
300
  *
290
301
  * @example
291
302
  * // With options object
@@ -299,7 +310,7 @@ const internals = {
299
310
  * // With config array only
300
311
  * defineZenoConfig([customConfig])
301
312
  */
302
- const defineZenoConfig = (arg1, arg2) => {
313
+ const defineZenoConfig = async (arg1, arg2) => {
303
314
  let options = {
304
315
  react: false,
305
316
  ts: false,
@@ -347,6 +358,17 @@ const defineZenoConfig = (arg1, arg2) => {
347
358
  options.nodeIgnoreDirs = [...options.reactDirs];
348
359
  }
349
360
 
361
+ // Load optional configs in parallel if needed
362
+ const [reactConfigResult, tsConfigResult] = await Promise.all([
363
+ options.react
364
+ ? configs.getReact({
365
+ reactDirs: options.reactDirs,
366
+ extensionsIgnorePattern: options.extensionsIgnorePattern,
367
+ })
368
+ : Promise.resolve([]),
369
+ options.ts ? configs.getTypescript() : Promise.resolve([]),
370
+ ]);
371
+
350
372
  return defineConfig([
351
373
  ...configs.getBase({
352
374
  ignoreExports: options.ignoreExports,
@@ -354,13 +376,8 @@ const defineZenoConfig = (arg1, arg2) => {
354
376
  extensionsIgnorePattern: options.extensionsIgnorePattern,
355
377
  }),
356
378
  ...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() : []),
379
+ ...reactConfigResult,
380
+ ...tsConfigResult,
364
381
 
365
382
  ...(config || []),
366
383