eslint-config-agent 2.0.0 → 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,5 +1,6 @@
1
1
  import js from '@eslint/js'
2
2
  import earlyReturn from 'eslint-plugin-early-return'
3
+ import jsxClassname from 'eslint-plugin-jsx-classname'
3
4
  import reactHooks from 'eslint-plugin-react-hooks'
4
5
  import { defineConfig } from 'eslint/config'
5
6
  import tseslint from 'typescript-eslint'
@@ -141,7 +142,14 @@ const config = defineConfig([
141
142
  // Examples files configuration
142
143
  ...examplesConfig,
143
144
 
144
- // 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)
145
153
  ...overridesConfig(sharedRestrictedSyntax, tsOnlyRestrictedSyntax),
146
154
  ])
147
155
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint-config-agent",
3
- "version": "2.0.0",
3
+ "version": "2.0.1",
4
4
  "description": "ESLint configuration package with TypeScript support",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -110,6 +110,7 @@
110
110
  "eslint-plugin-early-return": "^1.0.0",
111
111
  "eslint-plugin-error": "^1.3.0",
112
112
  "eslint-plugin-import": "^2.32.0",
113
+ "eslint-plugin-jsx-classname": "^1.0.1",
113
114
  "eslint-plugin-n": "^17.21.3",
114
115
  "eslint-plugin-no-optional-chaining": "^1.0.0",
115
116
  "eslint-plugin-preact": "^0.1.0",
package/plugins/index.js CHANGED
@@ -18,7 +18,6 @@ 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
20
  import preactPlugin from 'eslint-plugin-preact'
21
- import allRules from '../rules/index.js'
22
21
  import { noDefaultClassExportRule } from '../rules/no-default-class-export/index.js'
23
22
 
24
23
  // Centralized plugin configuration
@@ -39,7 +38,6 @@ export const plugins = {
39
38
  custom: {
40
39
  rules: {
41
40
  'no-default-class-export': noDefaultClassExportRule,
42
- 'jsx-classname-required': allRules.jsxClassNameRequiredRule,
43
41
  },
44
42
  },
45
43
  }
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 }