zeno-config 2.2.0 → 4.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
@@ -47,6 +47,26 @@ export default defineZenoConfig({
47
47
  });
48
48
  ```
49
49
 
50
+ #### React Compiler
51
+
52
+ If you're using or preparing to adopt [React Compiler](https://react.dev/learn/react-compiler), you can opt in to its ESLint rules:
53
+
54
+ ```javascript
55
+ import { defineZenoConfig } from 'zeno-config/eslint';
56
+
57
+ // Preparing a codebase — surface compiler violations as warnings
58
+ export default defineZenoConfig({
59
+ react: true,
60
+ reactCompiler: 'warn',
61
+ });
62
+
63
+ // Full enforcement — compiler rules as errors
64
+ export default defineZenoConfig({
65
+ react: true,
66
+ reactCompiler: true,
67
+ });
68
+ ```
69
+
50
70
  #### `engines` field in `package.json`
51
71
 
52
72
  Add an `engines` field to your `package.json` with your supported Node.js versions. Some rules for Node.js use this:
@@ -70,7 +90,7 @@ export default defineZenoConfig(
70
90
  ts: true,
71
91
 
72
92
  // Additional directories to ignore (added to defaults: node_modules, dist, build, coverage)
73
- ignoreDirs: ['out', '.next'],
93
+ ignores: ['out', '.next'],
74
94
 
75
95
  // If using .js extensions for React files, specify React directories
76
96
  reactDirs: ['src/client', 'src/components'],
@@ -166,6 +186,26 @@ Example:
166
186
  }
167
187
  ```
168
188
 
189
+ ### Gitignore
190
+
191
+ Includes a shared `.gitignore` template with common patterns for your projects. Run the following command to add any missing patterns to your project's `.gitignore` (or create one if it doesn't exist):
192
+
193
+ ```bash
194
+ npx zc-gitignore
195
+ ```
196
+
197
+ The command only adds patterns that aren't already present. You can also add it as a setup script:
198
+
199
+ ```json
200
+ {
201
+ "scripts": {
202
+ "setup:gitignore": "zc-gitignore"
203
+ }
204
+ }
205
+ ```
206
+
207
+ See [src/gitignore](src/gitignore) for the full list of included patterns.
208
+
169
209
  ### File Extensions Helpers
170
210
 
171
211
  Use in your build configs, webpack, etc:
@@ -194,18 +234,19 @@ import {
194
234
 
195
235
  ### `defineZenoConfig(options, additionalESLintConfig)`
196
236
 
197
- | Option | Type | Default | Description |
198
- | --------------------------- | ---------- | ----------- | --------------------------------------------------------------------------------------------- |
199
- | `react` | `boolean` | `false` | Enable React-specific rules |
200
- | `ts` | `boolean` | `false` | Enable TypeScript-specific rules |
201
- | `performanceMode` | `boolean` | `false` | Disables expensive rules for better performance |
202
- | `ignoreDirs` | `string[]` | `[]` | Additional directories to ignore (added to defaults: node_modules, dist, build, coverage) |
203
- | `reactDirs` | `string[]` | `[]` | Directories containing React files (for projects using .js for both React and Node) |
204
- | `nodeIgnoreDirs` | `string[]` | `[]` | Directories to ignore for Node-specific rules (defaults to `reactDirs` if not set) |
205
- | `ignoreExports` | `string[]` | `[]` | Export patterns to ignore for import/no-unresolved rule |
206
- | `additionalDevDependencies` | `string[]` | `[]` | Additional file patterns to allow dev dependencies in (for import/no-extraneous-dependencies) |
207
- | `extensionsIgnorePattern` | `object` | `{}` | Extension patterns to ignore for import/extensions rule |
208
- | `webpackConfig` | `string` | `undefined` | Path to webpack config for import resolver |
237
+ | Option | Type | Default | Description |
238
+ | --------------------------- | ----------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------- |
239
+ | `react` | `boolean` | `false` | Enable React-specific rules |
240
+ | `reactCompiler` | `boolean \| 'warn'` | `false` | Enable React Compiler rules. Set to `'warn'` to surface violations as warnings (for preparing a codebase), or `true` to enforce as errors |
241
+ | `ts` | `boolean` | `false` | Enable TypeScript-specific rules |
242
+ | `performanceMode` | `boolean` | `false` | Disables expensive rules for better performance |
243
+ | `ignores` | `string[]` | `[]` | Additional directories to ignore (added to defaults: node_modules, dist, build, coverage) |
244
+ | `reactDirs` | `string[]` | `[]` | Directories containing React files (for projects using .js for both React and Node) |
245
+ | `nodeIgnoreDirs` | `string[]` | `[]` | Directories to ignore for Node-specific rules (defaults to `reactDirs` if not set) |
246
+ | `ignoreExports` | `string[]` | `[]` | Export patterns to ignore for import/no-unresolved rule |
247
+ | `additionalDevDependencies` | `string[]` | `[]` | Additional file patterns to allow dev dependencies in (for import/no-extraneous-dependencies) |
248
+ | `extensionsIgnorePattern` | `object` | `{}` | Extension patterns to ignore for import/extensions rule |
249
+ | `webpackConfig` | `string` | `undefined` | Path to webpack config for import resolver |
209
250
 
210
251
  ## Advanced Usage
211
252
 
@@ -270,7 +311,7 @@ See the TypeScript configuration files:
270
311
  - `eslint-plugin-n` - Node.js specific rules ([rules](src/eslint/rules/nodePluginRules.js))
271
312
  - `eslint-plugin-prettier` - Prettier integration
272
313
  - `eslint-plugin-react` (optional) - React specific rules ([rules](src/eslint/rules/reactPluginRules.js))
273
- - `eslint-plugin-react-hooks` (optional) - React Hooks rules ([rules](src/eslint/rules/reactHooksPluginRules.js))
314
+ - `eslint-plugin-react-hooks` (optional) - React Hooks rules ([rules](src/eslint/rules/reactHooksPluginRules.js)) and React Compiler rules ([rules](src/eslint/rules/reactCompilerPluginRules.js))
274
315
  - `eslint-plugin-jsx-a11y` (optional) - Accessibility rules for JSX ([rules](src/eslint/rules/jsxA11yPluginRules.js))
275
316
  - `eslint-plugin-react-you-might-not-need-an-effect` (optional) - React Effect optimization ([rules](src/eslint/rules/reactYouMightNotNeedAnEffectPluginRules.js))
276
317
  - `typescript-eslint` (optional) - TypeScript rules ([rules](src/eslint/rules/typescriptPluginRules.js))
@@ -0,0 +1,84 @@
1
+ #!/usr/bin/env node
2
+
3
+ /* eslint-disable no-console */
4
+
5
+ import { readFileSync, writeFileSync, existsSync } from 'node:fs';
6
+ import { resolve, dirname } from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ const templatePath = resolve(__dirname, '..', 'src', 'gitignore');
11
+ const targetPath = resolve(process.cwd(), '.gitignore');
12
+
13
+ const template = readFileSync(templatePath, 'utf8');
14
+
15
+ if (!existsSync(targetPath)) {
16
+ writeFileSync(targetPath, template);
17
+ console.log('Created .gitignore');
18
+ process.exit(0);
19
+ }
20
+
21
+ function parseSections(content) {
22
+ const sections = [];
23
+ let current = null;
24
+
25
+ for (const line of content.split('\n')) {
26
+ if (line.startsWith('#')) {
27
+ if (current) {
28
+ sections.push(current);
29
+ }
30
+ current = { comments: [line], patterns: [] };
31
+ } else if (line.trim()) {
32
+ if (!current) {
33
+ current = { comments: [], patterns: [] };
34
+ }
35
+ current.patterns.push(line);
36
+ }
37
+ }
38
+
39
+ if (current) {
40
+ sections.push(current);
41
+ }
42
+ return sections;
43
+ }
44
+
45
+ const existing = readFileSync(targetPath, 'utf8');
46
+ const existingPatterns = new Set(
47
+ existing
48
+ .split('\n')
49
+ .map((line) => line.trim())
50
+ .filter((line) => line && !line.startsWith('#'))
51
+ );
52
+
53
+ const templateSections = parseSections(template);
54
+ const sectionsToAdd = [];
55
+
56
+ for (const section of templateSections) {
57
+ const missing = section.patterns.filter((p) => !existingPatterns.has(p));
58
+ if (missing.length > 0) {
59
+ sectionsToAdd.push({ comments: section.comments, patterns: missing });
60
+ }
61
+ }
62
+
63
+ if (sectionsToAdd.length === 0) {
64
+ console.log('.gitignore is already up to date');
65
+ process.exit(0);
66
+ }
67
+
68
+ const lines = sectionsToAdd.flatMap((section) => [
69
+ '',
70
+ ...section.comments,
71
+ ...section.patterns,
72
+ ]);
73
+ const updated = `${existing.trimEnd()}\n${lines.join('\n')}\n`;
74
+
75
+ writeFileSync(targetPath, updated);
76
+
77
+ const count = sectionsToAdd.reduce((sum, s) => sum + s.patterns.length, 0);
78
+ for (const section of sectionsToAdd) {
79
+ console.log(section.comments.join('\n'));
80
+ for (const p of section.patterns) {
81
+ console.log(` ${p}`);
82
+ }
83
+ }
84
+ console.log(`\nAdded ${count} pattern(s) to .gitignore`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zeno-config",
3
- "version": "2.2.0",
3
+ "version": "4.0.0",
4
4
  "description": "Preconfigured and opinionated ESLint, Prettier, and TypeScript setup",
5
5
  "author": "Rick Brenn <brenn.rick@gmail.com>",
6
6
  "license": "MIT",
@@ -42,8 +42,12 @@
42
42
  "default": "./src/extensions.js"
43
43
  }
44
44
  },
45
+ "bin": {
46
+ "zc-gitignore": "./bin/gitignore.js"
47
+ },
45
48
  "files": [
46
- "src/**"
49
+ "src/**",
50
+ "bin/**"
47
51
  ],
48
52
  "peerDependencies": {
49
53
  "eslint": "^9.39.2",
@@ -57,24 +61,24 @@
57
61
  },
58
62
  "devDependencies": {
59
63
  "eslint": "9.39.2",
60
- "prettier": "3.8.0",
64
+ "prettier": "3.8.1",
61
65
  "typescript": "5.9.3"
62
66
  },
63
67
  "dependencies": {
64
68
  "@eslint/js": "9.39.2",
65
- "@stylistic/eslint-plugin": "5.7.0",
69
+ "@stylistic/eslint-plugin": "5.10.0",
66
70
  "eslint-config-prettier": "10.1.8",
67
71
  "eslint-import-resolver-webpack": "^0.13.10",
68
- "eslint-plugin-import-x": "4.16.1",
72
+ "eslint-plugin-import-x": "4.16.2",
69
73
  "eslint-plugin-jsx-a11y": "6.10.2",
70
- "eslint-plugin-n": "17.23.2",
74
+ "eslint-plugin-n": "17.24.0",
71
75
  "eslint-plugin-prettier": "5.5.5",
72
76
  "eslint-plugin-react": "7.37.5",
73
77
  "eslint-plugin-react-hooks": "7.0.1",
74
- "eslint-plugin-react-you-might-not-need-an-effect": "0.8.5",
75
- "eslint-plugin-unicorn": "62.0.0",
76
- "globals": "17.0.0",
77
- "typescript-eslint": "8.53.1"
78
+ "eslint-plugin-react-you-might-not-need-an-effect": "0.9.2",
79
+ "eslint-plugin-unicorn": "63.0.0",
80
+ "globals": "17.4.0",
81
+ "typescript-eslint": "8.57.1"
78
82
  },
79
83
  "scripts": {
80
84
  "inspect": "eslint --inspect-config",
@@ -23,6 +23,8 @@ interface ReactConfigOptions {
23
23
  reactDirs?: string[];
24
24
  /** Extension patterns to ignore for import rules */
25
25
  extensionsIgnorePattern?: Record<string, string>;
26
+ /** Enable React Compiler rules. Set to 'warn' for warnings or true for errors. */
27
+ reactCompiler?: boolean | 'warn';
26
28
  }
27
29
 
28
30
  interface TypescriptConfigOptions {
@@ -33,12 +35,14 @@ interface TypescriptConfigOptions {
33
35
  interface DefineZenoConfigOptions {
34
36
  /** Enable React-specific rules */
35
37
  react?: boolean;
38
+ /** Enable React Compiler rules. Set to 'warn' for warnings or true for errors. */
39
+ reactCompiler?: boolean | 'warn';
36
40
  /** Enable TypeScript-specific rules */
37
41
  ts?: boolean;
38
42
  /** Disables expensive rules for performance */
39
43
  performanceMode?: boolean;
40
44
  /** Additional directories to ignore (added to defaults: dist, build) */
41
- ignoreDirs?: string[];
45
+ ignores?: string[];
42
46
  /** Directories containing React files (for projects using .js for both React and Node) */
43
47
  reactDirs?: string[];
44
48
  /** Directories to ignore for Node-specific rules only */
@@ -90,6 +94,9 @@ interface Rules {
90
94
  extensions?: string[];
91
95
  }) => Linter.RulesRecord;
92
96
  getReactHooksPluginRules: () => Linter.RulesRecord;
97
+ getReactCompilerPluginRules: (
98
+ mode?: boolean | 'warn'
99
+ ) => Linter.RulesRecord;
93
100
  getReactYouMightNotNeedAnEffectPluginRules: () => Linter.RulesRecord;
94
101
  getJsxA11yPluginRules: () => Linter.RulesRecord;
95
102
  }
@@ -15,6 +15,7 @@ import getBaseRules from './rules/baseRules.js';
15
15
  import getImportPluginRules from './rules/importPluginRules.js';
16
16
  import getReactPluginRules from './rules/reactPluginRules.js';
17
17
  import getReactHooksPluginRules from './rules/reactHooksPluginRules.js';
18
+ import getReactCompilerPluginRules from './rules/reactCompilerPluginRules.js';
18
19
  import getStylisticPluginRules from './rules/stylisticPluginRules.js';
19
20
  import getNodePluginRules from './rules/nodePluginRules.js';
20
21
  import getReactYouMightNotNeedAnEffectPluginRules from './rules/reactYouMightNotNeedAnEffectPluginRules.js';
@@ -142,6 +143,7 @@ const nodeConfig = (options = {}) => {
142
143
  * @param {Object} [options={}] - Configuration options.
143
144
  * @param {string[]} [options.reactDirs] - Directories containing React files (for projects using .js for both React and Node).
144
145
  * @param {Object} [options.extensionsIgnorePattern] - Extension patterns to ignore for import rules.
146
+ * @param {boolean|string} [options.reactCompiler=false] - Enable React Compiler rules. Set to 'warn' for warnings or true for errors.
145
147
  * @returns {Array} ESLint flat config array.
146
148
  */
147
149
  const reactConfig = (options = {}) => {
@@ -181,6 +183,9 @@ const reactConfig = (options = {}) => {
181
183
  rules: {
182
184
  ...getReactPluginRules({ extensions }),
183
185
  ...getReactHooksPluginRules(),
186
+ ...(options.reactCompiler
187
+ ? getReactCompilerPluginRules(options.reactCompiler)
188
+ : {}),
184
189
  ...getReactYouMightNotNeedAnEffectPluginRules(),
185
190
  ...getJsxA11yPluginRules(),
186
191
 
@@ -296,6 +301,7 @@ const internals = {
296
301
  getUnicornPluginRules,
297
302
  getReactPluginRules,
298
303
  getReactHooksPluginRules,
304
+ getReactCompilerPluginRules,
299
305
  getReactYouMightNotNeedAnEffectPluginRules,
300
306
  getJsxA11yPluginRules,
301
307
  },
@@ -306,9 +312,10 @@ const internals = {
306
312
  *
307
313
  * @param {Object|Array} arg1 - Options object or additional config array. If an array, treated as additional config.
308
314
  * @param {boolean} [arg1.react=false] - Enable React-specific rules.
315
+ * @param {boolean|string} [arg1.reactCompiler=false] - Enable React Compiler rules. Set to 'warn' for warnings or true for errors.
309
316
  * @param {boolean} [arg1.ts=true] - Enable TypeScript-specific rules.
310
317
  * @param {boolean} [arg1.performanceMode=false] - Disables expensive rules for performance.
311
- * @param {string[]} [arg1.ignoreDirs=[]] - Additional directories to ignore (added to defaults: dist, build).
318
+ * @param {string[]} [arg1.ignores=[]] - Additional directories to ignore (added to defaults: dist, build).
312
319
  * @param {string[]} [arg1.reactDirs=[]] - Directories containing React files (for projects using .js for both React and Node).
313
320
  * @param {string[]} [arg1.nodeIgnoreDirs=[]] - Directories to ignore for Node-specific rules only.
314
321
  * @param {string[]} [arg1.ignoreExports=[]] - Export patterns to ignore for import rules.
@@ -333,11 +340,12 @@ const internals = {
333
340
  const defineZenoConfig = (arg1, arg2) => {
334
341
  let options = {
335
342
  react: false,
343
+ reactCompiler: false,
336
344
  ts: false,
337
345
  performanceMode: false,
338
346
 
339
347
  // additional directories to ignore (added to defaults: dist, build)
340
- ignoreDirs: [],
348
+ ignores: [],
341
349
 
342
350
  // if a project uses .js file extension for both react and node files this will help separate the rules for each
343
351
  reactDirs: [],
@@ -358,8 +366,8 @@ const defineZenoConfig = (arg1, arg2) => {
358
366
  }
359
367
 
360
368
  // Ensure array options are arrays
361
- if (!Array.isArray(options.ignoreDirs)) {
362
- options.ignoreDirs = [];
369
+ if (!Array.isArray(options.ignores)) {
370
+ options.ignores = [];
363
371
  }
364
372
  if (!Array.isArray(options.reactDirs)) {
365
373
  options.reactDirs = [];
@@ -394,6 +402,7 @@ const defineZenoConfig = (arg1, arg2) => {
394
402
  ? configs.getReact({
395
403
  reactDirs: options.reactDirs,
396
404
  extensionsIgnorePattern: options.extensionsIgnorePattern,
405
+ reactCompiler: options.reactCompiler,
397
406
  })
398
407
  : [];
399
408
  const tsConfigResult = options.ts
@@ -401,7 +410,7 @@ const defineZenoConfig = (arg1, arg2) => {
401
410
  : [];
402
411
 
403
412
  return defineConfig([
404
- { ignores: [...defaultIgnoreDirs, ...options.ignoreDirs] },
413
+ { ignores: [...defaultIgnoreDirs, ...options.ignores] },
405
414
  ...configs.getBase({
406
415
  ignoreExports: options.ignoreExports,
407
416
  additionalDevDependencies: options.additionalDevDependencies,
@@ -190,7 +190,7 @@ const getBaseRules = () => {
190
190
  ],
191
191
 
192
192
  // https://eslint.org/docs/latest/rules/no-useless-assignment
193
- 'no-useless-assignment': 'error',
193
+ 'no-useless-assignment': 'off',
194
194
 
195
195
  // https://eslint.org/docs/latest/rules/no-useless-backreference
196
196
  'no-useless-backreference': 'error',
@@ -395,7 +395,7 @@ const getBaseRules = () => {
395
395
 
396
396
  // https://eslint.org/docs/latest/rules/no-implicit-coercion
397
397
  'no-implicit-coercion': [
398
- 'error',
398
+ 'off',
399
399
  {
400
400
  boolean: true,
401
401
  number: true,
@@ -488,7 +488,7 @@ const getBaseRules = () => {
488
488
  ],
489
489
 
490
490
  // https://eslint.org/docs/latest/rules/no-plusplus
491
- 'no-plusplus': ['error', { allowForLoopAfterthoughts: true }],
491
+ 'no-plusplus': ['off', { allowForLoopAfterthoughts: true }],
492
492
 
493
493
  // https://eslint.org/docs/latest/rules/no-proto
494
494
  'no-proto': 'error',
@@ -96,6 +96,9 @@ const getNodePluginRules = () => {
96
96
  // https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/prefer-global/console.md
97
97
  'n/prefer-global/console': 'error',
98
98
 
99
+ // https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/prefer-global/crypto.md
100
+ 'n/prefer-global/crypto': 'error',
101
+
99
102
  // https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/prefer-global/process.md
100
103
  'n/prefer-global/process': 'error',
101
104
 
@@ -105,6 +108,9 @@ const getNodePluginRules = () => {
105
108
  // https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/prefer-global/text-encoder.md
106
109
  'n/prefer-global/text-encoder': 'error',
107
110
 
111
+ // https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/prefer-global/timers.md
112
+ 'n/prefer-global/timers': 'error',
113
+
108
114
  // https://github.com/eslint-community/eslint-plugin-n/blob/master/docs/rules/prefer-global/url.md
109
115
  'n/prefer-global/url': 'error',
110
116
 
@@ -0,0 +1,24 @@
1
+ const getReactCompilerPluginRules = (mode) => {
2
+ const level = mode === 'warn' ? 'warn' : 'error';
3
+
4
+ return {
5
+ // https://github.com/facebook/react/tree/main/packages/eslint-plugin-react-hooks
6
+ 'react-hooks/config': level,
7
+ 'react-hooks/error-boundaries': level,
8
+ 'react-hooks/component-hook-factories': level,
9
+ 'react-hooks/gating': level,
10
+ 'react-hooks/globals': level,
11
+ 'react-hooks/immutability': level,
12
+ 'react-hooks/preserve-manual-memoization': level,
13
+ 'react-hooks/purity': level,
14
+ 'react-hooks/refs': level,
15
+ 'react-hooks/set-state-in-effect': 'warn',
16
+ 'react-hooks/set-state-in-render': level,
17
+ 'react-hooks/static-components': level,
18
+ 'react-hooks/unsupported-syntax': 'warn',
19
+ 'react-hooks/use-memo': level,
20
+ 'react-hooks/incompatible-library': 'warn',
21
+ };
22
+ };
23
+
24
+ export default getReactCompilerPluginRules;
@@ -1,26 +1,8 @@
1
1
  const getReactHooksPluginRules = () => {
2
2
  return {
3
3
  // https://github.com/facebook/react/tree/main/packages/eslint-plugin-react-hooks
4
- // Core hooks rules
5
4
  'react-hooks/rules-of-hooks': 'error',
6
5
  'react-hooks/exhaustive-deps': 'error',
7
-
8
- // React Compiler rules
9
- 'react-hooks/config': 'error',
10
- 'react-hooks/error-boundaries': 'error',
11
- 'react-hooks/component-hook-factories': 'error',
12
- 'react-hooks/gating': 'error',
13
- 'react-hooks/globals': 'error',
14
- 'react-hooks/immutability': 'error',
15
- 'react-hooks/preserve-manual-memoization': 'error',
16
- 'react-hooks/purity': 'error',
17
- 'react-hooks/refs': 'error',
18
- 'react-hooks/set-state-in-effect': 'warn',
19
- 'react-hooks/set-state-in-render': 'error',
20
- 'react-hooks/static-components': 'error',
21
- 'react-hooks/unsupported-syntax': 'warn',
22
- 'react-hooks/use-memo': 'error',
23
- 'react-hooks/incompatible-library': 'warn',
24
6
  };
25
7
  };
26
8
 
@@ -10,7 +10,6 @@ const getReactYouMightNotNeedAnEffectPluginRules = () => {
10
10
  'react-you-might-not-need-an-effect/no-pass-live-state-to-parent':
11
11
  'warn',
12
12
  'react-you-might-not-need-an-effect/no-pass-data-to-parent': 'warn',
13
- 'react-you-might-not-need-an-effect/no-pass-ref-to-parent': 'warn',
14
13
  'react-you-might-not-need-an-effect/no-initialize-state': 'warn',
15
14
  'react-you-might-not-need-an-effect/no-chain-state-updates': 'warn',
16
15
  'react-you-might-not-need-an-effect/no-derived-state': 'warn',
@@ -505,6 +505,10 @@ const getTypescriptPluginRules = () => {
505
505
  // requires type information
506
506
  '@typescript-eslint/strict-boolean-expressions': 'off',
507
507
 
508
+ // https://typescript-eslint.io/rules/strict-void-return
509
+ // requires type information
510
+ '@typescript-eslint/strict-void-return': 'off',
511
+
508
512
  // https://typescript-eslint.io/rules/switch-exhaustiveness-check
509
513
  // requires type information
510
514
  '@typescript-eslint/switch-exhaustiveness-check': 'off',
@@ -56,9 +56,8 @@ const getUnicornPluginRules = () => {
56
56
  // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/import-style.md
57
57
  'unicorn/import-style': 'off',
58
58
 
59
- // TODO: new rule, enable once released
60
59
  // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/isolated-functions.md
61
- // 'unicorn/isolated-functions': 'error',
60
+ 'unicorn/isolated-functions': 'error',
62
61
 
63
62
  // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/new-for-builtins.md
64
63
  'unicorn/new-for-builtins': 'error',
@@ -347,7 +346,7 @@ const getUnicornPluginRules = () => {
347
346
  'unicorn/prefer-prototype-methods': 'error',
348
347
 
349
348
  // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-query-selector.md
350
- 'unicorn/prefer-query-selector': 'warn',
349
+ 'unicorn/prefer-query-selector': 'off',
351
350
 
352
351
  // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-reflect-apply.md
353
352
  'unicorn/prefer-reflect-apply': 'warn',
@@ -386,7 +385,7 @@ const getUnicornPluginRules = () => {
386
385
  'unicorn/prefer-string-trim-start-end': 'warn',
387
386
 
388
387
  // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-structured-clone.md
389
- 'unicorn/prefer-structured-clone': 'error',
388
+ 'unicorn/prefer-structured-clone': 'off',
390
389
 
391
390
  // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-switch.md
392
391
  'unicorn/prefer-switch': 'off',
@@ -395,7 +394,7 @@ const getUnicornPluginRules = () => {
395
394
  'unicorn/prefer-ternary': 'off',
396
395
 
397
396
  // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-top-level-await.md
398
- 'unicorn/prefer-top-level-await': 'error',
397
+ 'unicorn/prefer-top-level-await': 'off',
399
398
 
400
399
  // https://github.com/sindresorhus/eslint-plugin-unicorn/blob/main/docs/rules/prefer-type-error.md
401
400
  'unicorn/prefer-type-error': 'warn',
package/src/gitignore ADDED
@@ -0,0 +1,60 @@
1
+ # Logs
2
+ logs
3
+ *.log
4
+ npm-debug.log*
5
+ yarn-debug.log*
6
+ yarn-error.log*
7
+ lerna-debug.log*
8
+ .pnpm-debug.log*
9
+
10
+ # Coverage directory
11
+ coverage
12
+
13
+ # Dependency directories
14
+ node_modules
15
+
16
+ # Build output
17
+ dist
18
+ build
19
+
20
+ # Environment variables
21
+ .env
22
+ .env.*
23
+ !.env.example
24
+
25
+ # pnpm
26
+ .pnpm-store
27
+
28
+ # npm
29
+ npm-debug.log*
30
+
31
+ # OS files
32
+ .DS_Store
33
+
34
+ # TypeScript cache
35
+ *.tsbuildinfo
36
+
37
+ # Optional npm cache directory
38
+ .npm
39
+
40
+ # Optional eslint cache
41
+ .eslintcache
42
+
43
+ # Output of 'npm pack'
44
+ *.tgz
45
+
46
+ # Editor directories and files
47
+ .vscode/*
48
+ !.vscode/extensions.json
49
+ .idea
50
+ *.suo
51
+ *.ntvs*
52
+ *.njsproj
53
+ *.sln
54
+ *.sw?
55
+
56
+ # temp lerna install file
57
+ *.lerna_backup
58
+
59
+ # storybook
60
+ storybook-static
@@ -2,30 +2,30 @@
2
2
  "$schema": "https://json.schemastore.org/tsconfig",
3
3
  "compilerOptions": {
4
4
  /* Language and Environment */
5
- "target": "ES2022", // output code
6
- "lib": ["ES2022"], // input code - Node.js ES support
5
+ "target": "ES2023",
6
+ "lib": ["ES2023"],
7
7
 
8
8
  /* Modules */
9
9
  "module": "NodeNext", // Node.js native ESM
10
10
  "moduleResolution": "NodeNext", // Node.js native ESM resolution
11
- "resolveJsonModule": true,
11
+ "moduleDetection": "force", // treat all files as modules
12
+ "verbatimModuleSyntax": true, // enforce explicit import type syntax and matching module syntax
12
13
 
13
14
  /* Emit */
14
- "outDir": "./dist",
15
15
  "noEmit": true, // using external tools for compilation
16
16
  "incremental": true, // cache type checking results
17
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.tsbuildinfo",
17
18
 
18
- /* Interop Constraints */
19
- "esModuleInterop": true, // CommonJS/ESM interop
20
- "allowSyntheticDefaultImports": true, // allows default imports from modules with no default export
21
- "isolatedModules": true, // ensures each file can be independently transpiled
19
+ /* Transpiler Compatibility */
20
+ "erasableSyntaxOnly": true, // disallow const enum, namespace, etc. for type-stripping tool compat
22
21
 
23
22
  /* Type Checking */
24
- "strict": true, // includes several rules it enables
23
+ "strict": true,
25
24
  "noUnusedLocals": false, // using @typescript-eslint/no-unused-vars instead
26
25
  "noUnusedParameters": false, // using @typescript-eslint/no-unused-vars instead
27
- "noFallthroughCasesInSwitch": true,
28
- "skipLibCheck": true, // skip dependency type checking (standard to set as true)
29
- "noUncheckedIndexedAccess": true
26
+ "noFallthroughCasesInSwitch": false, // using eslint no-fallthrough instead
27
+ "noUncheckedIndexedAccess": true, // force handling undefined on index access
28
+ "noUncheckedSideEffectImports": true, // validate side-effect imports resolve
29
+ "skipLibCheck": true // skip type checking of declaration files
30
30
  }
31
31
  }
@@ -3,11 +3,15 @@
3
3
  "extends": "./tsconfig.base.json",
4
4
  "compilerOptions": {
5
5
  /* Language and Environment */
6
- "lib": ["ES2022", "DOM", "DOM.Iterable"], // browser APIs
7
- "jsx": "react-jsx", // React 17+ jsx transform (automatic runtime / no React import)
6
+ "lib": ["ES2023", "DOM", "DOM.Iterable"], // browser APIs
7
+ "jsx": "react-jsx", // React 17+ automatic jsx transform
8
8
 
9
9
  /* Modules */
10
- "module": "ESNext", // needed since webpack/babel is handling compilation
11
- "moduleResolution": "bundler" // needed since webpack/babel is handling compilation
10
+ "module": "ESNext", // bundler handles module compilation
11
+ "moduleResolution": "bundler", // bundler-style resolution
12
+ "allowImportingTsExtensions": true, // allow .ts/.tsx imports (bundler resolves them)
13
+
14
+ /* Emit */
15
+ "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.react.tsbuildinfo"
12
16
  }
13
17
  }