eslint-config-agent 1.9.3 → 2.0.1

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.
@@ -86,15 +86,6 @@ export const overridesConfig = (
86
86
  },
87
87
  },
88
88
 
89
- // className requirement for JSX files
90
- {
91
- files: ['**/*.{tsx,jsx}'],
92
- ignores: ['**/*.stories.{js,jsx,ts,tsx}'],
93
- rules: {
94
- 'custom/jsx-classname-required': 'error',
95
- },
96
- },
97
-
98
89
  // Function and file length rules - strict error thresholds
99
90
  {
100
91
  files: ['**/*.{ts,tsx,js,jsx}'],
package/index.js CHANGED
@@ -1,4 +1,6 @@
1
1
  import js from '@eslint/js'
2
+ import earlyReturn from 'eslint-plugin-early-return'
3
+ import jsxClassname from 'eslint-plugin-jsx-classname'
2
4
  import reactHooks from 'eslint-plugin-react-hooks'
3
5
  import { defineConfig } from 'eslint/config'
4
6
  import tseslint from 'typescript-eslint'
@@ -104,23 +106,10 @@ const config = defineConfig([
104
106
  {
105
107
  plugins,
106
108
  },
107
- // Use recommended-latest if available (v5+), otherwise create flat config equivalent of legacy recommended
108
- ...(reactHooks.configs['recommended-latest']
109
- ? [reactHooks.configs['recommended-latest']]
110
- : [
111
- {
112
- name: 'react-hooks/recommended-flat',
113
- plugins: {
114
- 'react-hooks': reactHooks,
115
- },
116
- rules: {
117
- 'react-hooks/rules-of-hooks': 'error',
118
- 'react-hooks/exhaustive-deps': 'warn',
119
- },
120
- },
121
- ]),
109
+ reactHooks.configs['recommended-latest'],
122
110
  js.configs.recommended,
123
111
  ...tseslint.configs.recommended,
112
+ earlyReturn.configs.recommended,
124
113
 
125
114
  // Base plugin strict configs (error, default, guard-clauses)
126
115
  ...basePluginsConfig,
@@ -153,7 +142,14 @@ const config = defineConfig([
153
142
  // Examples files configuration
154
143
  ...examplesConfig,
155
144
 
156
- // Final overrides (index files, switch case, className, length rules)
145
+ // className requirement for JSX files (strict: errors + rejects Tailwind-only classNames)
146
+ {
147
+ ...jsxClassname.configs.strict,
148
+ files: ['**/*.{tsx,jsx}'],
149
+ ignores: ['**/*.stories.{js,jsx,ts,tsx}'],
150
+ },
151
+
152
+ // Final overrides (index files, switch case, length rules)
157
153
  ...overridesConfig(sharedRestrictedSyntax, tsOnlyRestrictedSyntax),
158
154
  ])
159
155
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-config-agent",
3
- "version": "1.9.3",
3
+ "version": "2.0.1",
4
4
  "description": "ESLint configuration package with TypeScript support",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -61,37 +61,17 @@
61
61
  "author": "tupe12334",
62
62
  "repository": {
63
63
  "type": "git",
64
- "url": "git+https://github.com/tupe12334/eslint-config.git"
64
+ "url": "git+https://github.com/tupe12334/eslint-config-agent.git"
65
65
  },
66
66
  "bugs": {
67
- "url": "https://github.com/tupe12334/eslint-config/issues"
67
+ "url": "https://github.com/tupe12334/eslint-config-agent/issues"
68
68
  },
69
- "homepage": "https://github.com/tupe12334/eslint-config#readme",
69
+ "homepage": "https://github.com/tupe12334/eslint-config-agent#readme",
70
70
  "license": "MIT",
71
71
  "publishConfig": {
72
72
  "access": "public"
73
73
  },
74
74
  "packageManager": "pnpm@10.18.2",
75
- "peerDependencies": {
76
- "@eslint/eslintrc": "^3.3.1",
77
- "@eslint/js": "^9.34.0",
78
- "@typescript-eslint/eslint-plugin": "^8.40.0",
79
- "@typescript-eslint/parser": "^8.40.0",
80
- "eslint": "^9.34.0",
81
- "eslint-plugin-class-export": "^1.0.1",
82
- "eslint-plugin-import": "^2.32.0",
83
- "eslint-plugin-n": "^17.21.3",
84
- "eslint-plugin-react": "^7.37.5",
85
- "eslint-plugin-react-hooks": "^5.2.0",
86
- "eslint-plugin-security": "^3.0.1",
87
- "eslint-plugin-storybook": "^9.1.5",
88
- "typescript-eslint": "^8.40.0"
89
- },
90
- "peerDependenciesMeta": {
91
- "eslint-plugin-preact": {
92
- "optional": true
93
- }
94
- },
95
75
  "devDependencies": {
96
76
  "@commitlint/cli": "^20.1.0",
97
77
  "@commitlint/config-conventional": "^20.0.0",
@@ -119,12 +99,28 @@
119
99
  "typescript-eslint": "^8.46.1"
120
100
  },
121
101
  "dependencies": {
102
+ "@eslint/eslintrc": "^3.3.1",
103
+ "@eslint/js": "^9.34.0",
104
+ "@typescript-eslint/eslint-plugin": "^8.40.0",
105
+ "@typescript-eslint/parser": "^8.40.0",
106
+ "eslint": "^9.34.0",
107
+ "eslint-plugin-class-export": "^1.0.1",
122
108
  "eslint-plugin-ddd": "^0.5.2",
123
109
  "eslint-plugin-default": "^1.1.0",
110
+ "eslint-plugin-early-return": "^1.0.0",
124
111
  "eslint-plugin-error": "^1.3.0",
112
+ "eslint-plugin-import": "^2.32.0",
113
+ "eslint-plugin-jsx-classname": "^1.0.1",
114
+ "eslint-plugin-n": "^17.21.3",
125
115
  "eslint-plugin-no-optional-chaining": "^1.0.0",
116
+ "eslint-plugin-preact": "^0.1.0",
117
+ "eslint-plugin-react": "^7.37.5",
118
+ "eslint-plugin-react-hooks": "^5.2.0",
126
119
  "eslint-plugin-required-exports": "^0.2.0",
120
+ "eslint-plugin-security": "^3.0.1",
127
121
  "eslint-plugin-single-export": "^1.1.2",
128
- "globals": "^16.4.0"
122
+ "eslint-plugin-storybook": "^9.1.5",
123
+ "globals": "^16.4.0",
124
+ "typescript-eslint": "^8.40.0"
129
125
  }
130
126
  }
package/plugins/index.js CHANGED
@@ -17,17 +17,9 @@ import errorPlugin from 'eslint-plugin-error'
17
17
  import defaultPlugin from 'eslint-plugin-default'
18
18
  import noOptionalChainingPlugin from 'eslint-plugin-no-optional-chaining'
19
19
  import dddPlugin from 'eslint-plugin-ddd'
20
- import allRules from '../rules/index.js'
20
+ import preactPlugin from 'eslint-plugin-preact'
21
21
  import { noDefaultClassExportRule } from '../rules/no-default-class-export/index.js'
22
22
 
23
- // Conditionally import preact plugin if available
24
- let preactPlugin = null
25
- try {
26
- preactPlugin = (await import('eslint-plugin-preact')).default
27
- } catch {
28
- // eslint-plugin-preact is not available
29
- }
30
-
31
23
  // Centralized plugin configuration
32
24
  export const plugins = {
33
25
  react: reactPlugin,
@@ -42,11 +34,10 @@ export const plugins = {
42
34
  default: defaultPlugin,
43
35
  'no-optional-chaining': noOptionalChainingPlugin,
44
36
  ddd: dddPlugin,
45
- ...(preactPlugin && { preact: preactPlugin }),
37
+ preact: preactPlugin,
46
38
  custom: {
47
39
  rules: {
48
40
  'no-default-class-export': noDefaultClassExportRule,
49
- 'jsx-classname-required': allRules.jsxClassNameRequiredRule,
50
41
  },
51
42
  },
52
43
  }
@@ -119,26 +119,28 @@ export const errorOnlyExportsRule = {
119
119
  // Only check on program exit to ensure we've seen all exports
120
120
  },
121
121
  'Program:exit'(node) {
122
- if (isErrorOnlyFile(context)) {
123
- // Check if the file already has the eslint-disable comment
124
- const sourceCode = context.sourceCode || context.getSourceCode()
125
- const comments = sourceCode.getAllComments()
126
-
127
- const hasDisableComment = comments.some(
128
- comment =>
129
- comment.value.includes('eslint-disable ddd/require-spec-file') ||
130
- comment.value.includes(
131
- 'eslint-disable-next-line ddd/require-spec-file'
132
- )
133
- )
134
-
135
- // Only report if the disable comment is not present
136
- if (!hasDisableComment) {
137
- context.report({
138
- node,
139
- messageId: 'errorOnlyFile',
140
- })
141
- }
122
+ if (!isErrorOnlyFile(context)) {
123
+ return
124
+ }
125
+
126
+ // Check if the file already has the eslint-disable comment
127
+ const sourceCode = context.sourceCode || context.getSourceCode()
128
+ const comments = sourceCode.getAllComments()
129
+
130
+ const hasDisableComment = comments.some(
131
+ comment =>
132
+ comment.value.includes('eslint-disable ddd/require-spec-file') ||
133
+ comment.value.includes(
134
+ 'eslint-disable-next-line ddd/require-spec-file'
135
+ )
136
+ )
137
+
138
+ // Only report if the disable comment is not present
139
+ if (!hasDisableComment) {
140
+ context.report({
141
+ node,
142
+ messageId: 'errorOnlyFile',
143
+ })
142
144
  }
143
145
  },
144
146
  }
package/rules/index.js CHANGED
@@ -22,7 +22,6 @@ import { noTypeAssertionsConfig } from './no-type-assertions/index.js'
22
22
  import { noExportSpecifiersConfig } from './no-empty-exports/index.js'
23
23
  import { noClassPropertyDefaultsConfig } from './no-class-property-defaults/index.js'
24
24
  import { noDefaultClassExportRules } from './no-default-class-export/index.js'
25
- import { jsxClassNameRequiredRule } from './jsx-classname-required/index.js'
26
25
  import { noNullishCoalescingConfig } from './nullish-coalescing/index.js'
27
26
  import { switchStatementsReturnTypeConfigs } from './switch-statements-return-type/index.js'
28
27
  import { switchCaseFunctionsReturnTypeConfigs } from './switch-case-functions-return-type/index.js'
@@ -49,7 +48,6 @@ const allRules = {
49
48
  noExportSpecifiersConfig,
50
49
  noClassPropertyDefaultsConfig,
51
50
  noDefaultClassExportRules,
52
- jsxClassNameRequiredRule,
53
51
  noNullishCoalescingConfig,
54
52
  switchStatementsReturnTypeConfigs,
55
53
  switchCaseFunctionsReturnTypeConfigs,
@@ -79,7 +77,6 @@ export {
79
77
  noExportSpecifiersConfig,
80
78
  noClassPropertyDefaultsConfig,
81
79
  noDefaultClassExportRules,
82
- jsxClassNameRequiredRule,
83
80
  noNullishCoalescingConfig,
84
81
  switchStatementsReturnTypeConfigs,
85
82
  switchCaseFunctionsReturnTypeConfigs,
@@ -1,95 +0,0 @@
1
- /**
2
- * ESLint rule to require className attribute on HTML elements in JSX
3
- *
4
- * This rule enforces that all HTML elements in JSX must have a non-empty className attribute.
5
- * It excludes React components (starting with capital letters), fragments, and title elements.
6
- *
7
- * Examples:
8
- * - ❌ <div>Content</div>
9
- * - ❌ <div className="">Content</div>
10
- * - ✅ <div className="container">Content</div>
11
- * - ✅ <MyComponent>Content</MyComponent> (ignored - React component)
12
- * - ✅ <Fragment>Content</Fragment> (ignored - fragment)
13
- * - ✅ <React.Fragment>Content</React.Fragment> (ignored - React fragment)
14
- * - ✅ <React.StrictMode>Content</React.StrictMode> (ignored - React component)
15
- * - ✅ <title>Page Title</title> (ignored - title element)
16
- */
17
-
18
- const jsxClassNameRequiredRule = {
19
- meta: {
20
- type: 'layout',
21
- docs: {
22
- description:
23
- 'Require non-empty className attribute on HTML elements in JSX',
24
- category: 'Stylistic Issues',
25
- recommended: false,
26
- },
27
- fixable: null,
28
- schema: [],
29
- messages: {
30
- missingClassName: 'HTML elements must have a className attribute.',
31
- emptyClassName:
32
- 'HTML elements must have a non-empty className attribute.',
33
- },
34
- },
35
-
36
- create(context) {
37
- return {
38
- JSXOpeningElement(node) {
39
- // Skip if this is a React component (starts with capital letter)
40
- if (
41
- node.name.type === 'JSXIdentifier' &&
42
- /^[A-Z]/.test(node.name.name)
43
- ) {
44
- return
45
- }
46
-
47
- // Skip if this is Fragment
48
- if (
49
- node.name.type === 'JSXIdentifier' &&
50
- node.name.name === 'Fragment'
51
- ) {
52
- return
53
- }
54
-
55
- // Skip if this is React.Something (like React.Fragment, React.StrictMode, etc.)
56
- if (
57
- node.name.type === 'JSXMemberExpression' &&
58
- node.name.object.name === 'React' &&
59
- /^[A-Z]/.test(node.name.property.name)
60
- ) {
61
- return
62
- }
63
-
64
- // Skip if this is a title element (used in document head)
65
- if (node.name.type === 'JSXIdentifier' && node.name.name === 'title') {
66
- return
67
- }
68
-
69
- // Find className attribute
70
- const classNameAttr = node.attributes.find(
71
- attr => attr.type === 'JSXAttribute' && attr.name.name === 'className'
72
- )
73
-
74
- if (!classNameAttr) {
75
- context.report({
76
- node,
77
- messageId: 'missingClassName',
78
- })
79
- return
80
- }
81
-
82
- // Check if className is an empty string
83
- const value = classNameAttr.value
84
- if (value && value.type === 'Literal' && value.value === '') {
85
- context.report({
86
- node,
87
- messageId: 'emptyClassName',
88
- })
89
- }
90
- },
91
- }
92
- },
93
- }
94
-
95
- export { jsxClassNameRequiredRule }