@shayanthenerd/eslint-config 0.33.0 → 0.34.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
@@ -35,7 +35,7 @@ Legend:
35
35
  | [TypeScript][plugin-ts] | 🔍  |
36
36
  | [Markdown][plugin-md] | ✅  |
37
37
  | [HTML][plugin-html] | ⚙️  |
38
- | [CSS][plugin-css] | ⚙️  |
38
+ | [CSS][plugin-css] ([eslint-cssicorn][plugin-cssicorn]) | ⚙️  |
39
39
  | **Formatting** | |
40
40
  | [Stylistic][plugin-stylistic] | ✅  |
41
41
  | [Perfectionist][plugin-perfectionist] | ✅  |
@@ -768,7 +768,7 @@ This project was inspired by the work of [Anthony Fu][antfu], whose generous con
768
768
  [MIT][license] License © 2025-PRESENT — [Shayan Zamani][ShayanTheNerd]
769
769
 
770
770
  <!-- Badges -->
771
- [license]: ./LICENSE
771
+ [license]: LICENSE
772
772
  [license-badge]: https://img.shields.io/badge/License-MIT-blue.svg?logoColor=FEFEFE&labelColor=3B82F6&color=3B82F6
773
773
  [npm-version-badge]: https://img.shields.io/npm/v/@shayanthenerd/eslint-config?label=&logo=npm&logoColor=FEFEFE&labelColor=3B82F6&color=3B82F6
774
774
  [npmx]: https://www.npmjs.com/package/@shayanthenerd/eslint-config
@@ -782,6 +782,7 @@ This project was inspired by the work of [Anthony Fu][antfu], whose generous con
782
782
  [plugin-astro]: https://ota-meshi.github.io/eslint-plugin-astro
783
783
  [plugin-baseline]: https://baselinejs.vercel.app
784
784
  [plugin-css]: https://github.com/eslint/css
785
+ [plugin-cssicorn]: https://github.com/sindresorhus/eslint-cssicorn
785
786
  [plugin-cypress]: https://github.com/cypress-io/eslint-plugin-cypress
786
787
  [plugin-html]: https://html-eslint.org
787
788
  [plugin-html-react]: https://html-eslint.org/docs/react/getting-started
@@ -815,7 +816,7 @@ This project was inspired by the work of [Anthony Fu][antfu], whose generous con
815
816
 
816
817
  <!-- References -->
817
818
  [antfu]: https://github.com/antfu
818
- [contributing]: ./.github/CONTRIBUTING.md
819
+ [contributing]: .github/CONTRIBUTING.md
819
820
  [eslint]: https://eslint.org
820
821
  [online-preview]: https://eslintconfig.netlify.app
821
822
  [eslint-config-ts-setup]: https://eslint.org/docs/latest/use/configure/configuration-files#typescript-configuration-files
@@ -3,12 +3,12 @@ import { defaultOptions } from "../helpers/options/defaultOptions.mjs";
3
3
  import { isEnabled } from "../utils/isEnabled.mjs";
4
4
  import { getCssRules } from "../rules/css.mjs";
5
5
  import { mergeConfigs } from "eslint-flat-config-utils";
6
- import eslintPluginUnicorn from "eslint-plugin-unicorn";
6
+ import eslintPluginCssicorn from "eslint-cssicorn";
7
7
  import eslintPluginCss from "@eslint/css";
8
8
  import { tailwind3, tailwind4 } from "tailwind-csstree";
9
9
  //#region src/configs/css.ts
10
10
  function getCssConfig(options) {
11
- const { css, unicorn, tailwind } = options.configs;
11
+ const { css, tailwind } = options.configs;
12
12
  const { overrides } = isEnabled(css) ? css : defaultOptions.configs.css;
13
13
  const tailwindSyntax = isEnabled(tailwind) && tailwind.entryPoint ? tailwind4 : tailwind3;
14
14
  const cssConfig = {
@@ -16,7 +16,7 @@ function getCssConfig(options) {
16
16
  files: [globs.css],
17
17
  plugins: {
18
18
  css: eslintPluginCss,
19
- ...isEnabled(unicorn) && { unicorn: eslintPluginUnicorn }
19
+ cssicorn: eslintPluginCssicorn
20
20
  },
21
21
  language: "css/css",
22
22
  languageOptions: {
@@ -23,11 +23,12 @@ function enableDetectedConfigs(options) {
23
23
  "storybook": options.configs?.test?.storybook === false,
24
24
  "@playwright/test": options.configs?.test?.playwright === false
25
25
  };
26
+ const isAstroDetected = isPackageDetected("astro", options);
26
27
  const autoDetectedPackages = {
27
28
  typescript: isPackageDetected("typescript", options),
28
29
  zod: isPackageDetected("zod", options),
29
- astro: isPackageDetected("astro", options),
30
- eslintPluginJsxA11yX: isPackageDetected("eslint-plugin-jsx-a11y-x", options),
30
+ astro: isAstroDetected,
31
+ eslintPluginJsxA11yX: isAstroDetected && isPackageDetected("eslint-plugin-jsx-a11y-x", options),
31
32
  react: isPackageDetected("react", options),
32
33
  next: isPackageDetected("next", options),
33
34
  tanstackStart: isPackageDetected("@tanstack/react-start", options),
@@ -1,6 +1,5 @@
1
1
  import { defaultOptions } from "../helpers/options/defaultOptions.mjs";
2
2
  import { isEnabled } from "../utils/isEnabled.mjs";
3
- import { isTruthy } from "../utils/isTruthy.mjs";
4
3
  //#region src/rules/css.ts
5
4
  const allowedPhysicalUnits = [
6
5
  "cqh",
@@ -47,10 +46,10 @@ const allowedPhysicalProperties = [
47
46
  "contain-intrinsic-height"
48
47
  ];
49
48
  function getCssRules(options) {
50
- const { css, vue, unicorn, tailwind, baseline } = options.configs;
49
+ const { css, tailwind, baseline } = options.configs;
51
50
  const { allowedUnknownPseudoSelectors: userAllowedUnknownPseudoSelectors } = isEnabled(css) ? css : defaultOptions.configs.css;
52
51
  const { allowedAtRules: userAllowedAtRules, allowedFunctions: userAllowedFunctions, allowedMediaConditions: userAllowedMediaConditions, allowedProperties: userAllowedProperties, allowedPropertyValues: userAllowedPropertyValues, allowedSelectors: userAllowedSelectors, allowedUnits: userAllowedUnits } = isEnabled(baseline) ? baseline.css : defaultOptions.configs.baseline.css;
53
- const cssRules = {
52
+ return {
54
53
  "css/font-family-fallbacks": "warn",
55
54
  "css/no-duplicate-imports": "error",
56
55
  "css/no-duplicate-keyframe-selectors": "error",
@@ -90,36 +89,29 @@ function getCssRules(options) {
90
89
  },
91
90
  allowSelectors: ["selection", ...userAllowedSelectors],
92
91
  allowUnits: userAllowedUnits
93
- }] : "off"
92
+ }] : "off",
93
+ "cssicorn/lowercase": "error",
94
+ "cssicorn/no-declarations-after-nested-rules": "warn",
95
+ "cssicorn/no-deprecated-features": "error",
96
+ "cssicorn/no-descending-specificity": "warn",
97
+ "cssicorn/no-duplicate-font-family-names": "error",
98
+ "cssicorn/no-duplicate-properties": "warn",
99
+ "cssicorn/no-duplicate-selectors": "warn",
100
+ "cssicorn/no-invalid-media-features": "error",
101
+ "cssicorn/no-nesting-with-mixed-specificity": "warn",
102
+ "cssicorn/no-redundant-nested-style-rules": "warn",
103
+ "cssicorn/no-redundant-shorthand-values": "warn",
104
+ "cssicorn/no-self-referencing-custom-properties": "error",
105
+ "cssicorn/no-unknown-animations": "error",
106
+ "cssicorn/no-unknown-annotations": "error",
107
+ "cssicorn/no-unknown-pseudo-selectors": ["error", { allow: userAllowedUnknownPseudoSelectors }],
108
+ "cssicorn/no-unscoped-nesting-selector": isEnabled(tailwind) ? "error" : ["error", { scopingRootAtRules: [] }],
109
+ "cssicorn/no-zero-length-unit": "warn",
110
+ "cssicorn/prefer-explicit-viewport-units": "warn",
111
+ "cssicorn/prefer-media-feature-range-syntax": "warn",
112
+ "cssicorn/prefer-modern-syntax": "warn",
113
+ "cssicorn/require-property-descriptors": "error"
94
114
  };
95
- const unicornRules = {
96
- "unicorn/no-deprecated-css-features": "error",
97
- "unicorn/no-duplicate-css-selectors": "warn",
98
- "unicorn/no-duplicate-font-family-names": "error",
99
- "unicorn/no-invalid-media-features": "error",
100
- "unicorn/no-nesting-with-mixed-specificity": "warn",
101
- "unicorn/no-redundant-nested-style-rules": "warn",
102
- "unicorn/no-shorthand-property-overrides": "warn",
103
- "unicorn/no-unknown-css-annotations": "error",
104
- "unicorn/no-unknown-pseudo-selectors": ["error", { allow: [
105
- "::-ms-reveal",
106
- ":-webkit-autofill",
107
- "::-webkit-inner-spin-button",
108
- "::-webkit-search-cancel-button",
109
- "::-webkit-search-results-button",
110
- ...isEnabled(vue) ? [
111
- ":deep",
112
- ":global",
113
- ":slotted"
114
- ] : [],
115
- ...userAllowedUnknownPseudoSelectors
116
- ].filter(isTruthy) }],
117
- "unicorn/no-unscoped-css-nesting-selector": isEnabled(tailwind) ? ["error", { scopingRootAtRules: ["utility", "custom-variant"] }] : "error",
118
- "unicorn/prefer-explicit-viewport-units": "warn",
119
- "unicorn/prefer-media-feature-range-syntax": "warn"
120
- };
121
- if (isEnabled(unicorn)) Object.assign(cssRules, unicornRules);
122
- return cssRules;
123
115
  }
124
116
  //#endregion
125
117
  export { getCssRules };
@@ -79,9 +79,16 @@ function getHtmlRules(options) {
79
79
  { enforceTemplatedAttrValue: true }
80
80
  ]
81
81
  };
82
+ const unicornRules = {
83
+ "unicorn/consistent-compound-words": "warn",
84
+ "unicorn/no-ineffective-csp-directives": "error",
85
+ "unicorn/no-invalid-file-input-accept": "error",
86
+ "unicorn/no-invalid-integrity": "error",
87
+ "unicorn/relative-url-style": "warn"
88
+ };
82
89
  if (isEnabled(stylistic)) Object.assign(htmlRules, stylisticRules);
90
+ if (isEnabled(unicorn)) Object.assign(htmlRules, unicornRules);
83
91
  if (isEnabled(tailwind)) htmlRules["better-tailwindcss/no-duplicate-classes"] = "off";
84
- if (isEnabled(unicorn)) htmlRules["unicorn/no-invalid-file-input-accept"] = "error";
85
92
  return htmlRules;
86
93
  }
87
94
  //#endregion
@@ -47,7 +47,13 @@ function getMarkdownRules(options) {
47
47
  "markdown/require-alt-text": "warn",
48
48
  "markdown/table-column-count": isCommonMark ? "off" : ["error", { checkMissingCells: true }]
49
49
  };
50
- if (isEnabled(unicorn)) markdownRules["unicorn/no-missing-local-resource"] = "error";
50
+ const unicornRules = {
51
+ "unicorn/no-javascript-url": "error",
52
+ "unicorn/no-empty-link-text": "error",
53
+ "unicorn/no-missing-local-resource": "error",
54
+ "unicorn/relative-url-style": "warn"
55
+ };
56
+ if (isEnabled(unicorn)) Object.assign(markdownRules, unicornRules);
51
57
  return markdownRules;
52
58
  }
53
59
  //#endregion
@@ -14,7 +14,7 @@ const commonCallees = [
14
14
  "ctl"
15
15
  ];
16
16
  function getReactRules(options) {
17
- const { react, unicorn, tailwind, baseline, stylistic, typescript } = options.configs;
17
+ const { react, tailwind, baseline, stylistic, typescript } = options.configs;
18
18
  const { imageComponents: userImageComponents, anchorComponents: userAnchorComponents, headingComponents: userHeadingComponents } = isEnabled(react) && isEnabled(react.accessibility) ? react.accessibility : defaultOptions.configs.react.accessibility;
19
19
  const isTypescriptEnabled = isEnabled(typescript);
20
20
  const reactRules = {
@@ -161,7 +161,6 @@ function getReactRules(options) {
161
161
  reactRules["better-tailwindcss/no-duplicate-classes"] = "off";
162
162
  if (tailwind.multilineSort) reactRules["@html-eslint/react/classname-spacing"] = "off";
163
163
  }
164
- if (isEnabled(unicorn)) reactRules["unicorn/no-invalid-file-input-accept"] = "error";
165
164
  return reactRules;
166
165
  }
167
166
  //#endregion
@@ -49,6 +49,7 @@ function getTypescriptRules(options) {
49
49
  "@typescript-eslint/no-unsafe-assignment": "warn",
50
50
  "@typescript-eslint/no-unsafe-call": "warn",
51
51
  "@typescript-eslint/no-unsafe-declaration-merging": "warn",
52
+ "@typescript-eslint/no-unsafe-enum-assignment": "error",
52
53
  "@typescript-eslint/no-unsafe-enum-comparison": "error",
53
54
  "@typescript-eslint/no-unsafe-function-type": "warn",
54
55
  "@typescript-eslint/no-unsafe-member-access": "warn",
@@ -64,11 +64,22 @@ function getUnicornRules(options) {
64
64
  "unicorn/no-for-loop": "warn",
65
65
  "unicorn/no-immediate-mutation": "warn",
66
66
  "unicorn/no-impossible-length-comparison": "error",
67
+ "unicorn/no-incomplete-accessor-override": "error",
67
68
  "unicorn/no-incorrect-query-selector": "error",
68
69
  "unicorn/no-incorrect-template-string-interpolation": "error",
70
+ "unicorn/no-ineffective-csp-directives": "error",
71
+ "unicorn/no-invalid-boolean-attribute-value": "error",
69
72
  "unicorn/no-invalid-character-comparison": "error",
73
+ "unicorn/no-invalid-dom-token": "error",
70
74
  "unicorn/no-invalid-fetch-options": "error",
75
+ "unicorn/no-invalid-file-input-accept": "error",
76
+ "unicorn/no-invalid-intl-options": "error",
77
+ "unicorn/no-invalid-property-descriptor": "error",
71
78
  "unicorn/no-invalid-remove-event-listener": "error",
79
+ "unicorn/no-invalid-response-options": "error",
80
+ "unicorn/no-invalid-style-set-property": "error",
81
+ "unicorn/no-invalid-temporal-arithmetic": "error",
82
+ "unicorn/no-invalid-url-protocol-comparison": "error",
72
83
  "unicorn/no-invalid-well-known-symbol-methods": "error",
73
84
  "unicorn/no-late-current-target-access": "warn",
74
85
  "unicorn/no-late-event-control": "error",
@@ -87,6 +98,7 @@ function getUnicornRules(options) {
87
98
  "unicorn/no-object-as-default-parameter": "warn",
88
99
  "unicorn/no-object-methods-with-collections": "warn",
89
100
  "unicorn/no-optional-chaining-on-undeclared-variable": "error",
101
+ "unicorn/no-prevent-default-in-passive-listener": "error",
90
102
  "unicorn/no-redundant-comparison": "warn",
91
103
  "unicorn/no-return-array-push": "warn",
92
104
  "unicorn/no-selector-as-dom-name": "error",
@@ -104,6 +116,7 @@ function getUnicornRules(options) {
104
116
  "unicorn/no-unnecessary-fetch-options": "warn",
105
117
  "unicorn/no-unnecessary-global-this": "warn",
106
118
  "unicorn/no-unnecessary-nested-ternary": "warn",
119
+ "unicorn/no-unnecessary-parameters": "warn",
107
120
  "unicorn/no-unnecessary-polyfills": "warn",
108
121
  "unicorn/no-unnecessary-slice-end": "warn",
109
122
  "unicorn/no-unnecessary-splice": "warn",
@@ -112,11 +125,13 @@ function getUnicornRules(options) {
112
125
  "unicorn/no-unreadable-iife": "warn",
113
126
  "unicorn/no-unreadable-new-expression": "warn",
114
127
  "unicorn/no-unsafe-buffer-conversion": "warn",
128
+ "unicorn/no-unsafe-json-serialization": "error",
115
129
  "unicorn/no-unsafe-promise-all-settled-values": "error",
116
130
  "unicorn/no-unsafe-property-key": "error",
117
131
  "unicorn/no-unused-builtin-method-return": "warn",
118
132
  "unicorn/no-unused-iterator-helper": "warn",
119
133
  "unicorn/no-unused-properties": "warn",
134
+ "unicorn/no-url-in-search-params": "warn",
120
135
  "unicorn/no-useless-boolean-cast": "warn",
121
136
  "unicorn/no-useless-collection-argument": "warn",
122
137
  "unicorn/no-useless-compound-assignment": "warn",
@@ -164,7 +179,10 @@ function getUnicornRules(options) {
164
179
  "unicorn/prefer-class-fields": "warn",
165
180
  "unicorn/prefer-classlist-toggle": "warn",
166
181
  "unicorn/prefer-code-point": "error",
167
- "unicorn/prefer-combined-guards": ["warn", { checkCompoundConditions: true }],
182
+ "unicorn/prefer-combined-guards": ["warn", {
183
+ checkCompoundConditions: true,
184
+ checkMultiStatementBodies: true
185
+ }],
168
186
  "unicorn/prefer-continue": ["warn", { maximumStatements: 3 }],
169
187
  "unicorn/prefer-date-now": "warn",
170
188
  "unicorn/prefer-direct-iteration": "warn",
@@ -195,6 +213,7 @@ function getUnicornRules(options) {
195
213
  "unicorn/prefer-iterator-zip": "warn",
196
214
  "unicorn/prefer-json-import": "warn",
197
215
  "unicorn/prefer-keyboard-event-key": "error",
216
+ "unicorn/prefer-literal-ascii": "warn",
198
217
  "unicorn/prefer-location-assign": "warn",
199
218
  "unicorn/prefer-logical-operator-over-ternary": "warn",
200
219
  "unicorn/prefer-map-from-entries": "warn",
@@ -219,6 +238,7 @@ function getUnicornRules(options) {
219
238
  "unicorn/prefer-optional-catch-binding": "warn",
220
239
  "unicorn/prefer-path2d": "warn",
221
240
  "unicorn/prefer-private-class-fields": "warn",
241
+ "unicorn/prefer-promise-static-methods": "warn",
222
242
  "unicorn/prefer-promise-try": "warn",
223
243
  "unicorn/prefer-promise-with-resolvers": "warn",
224
244
  "unicorn/prefer-queue-microtask": "warn",
@@ -229,9 +249,10 @@ function getUnicornRules(options) {
229
249
  "unicorn/prefer-scoped-selector": "warn",
230
250
  "unicorn/prefer-set-methods": "warn",
231
251
  "unicorn/prefer-set-size": "warn",
252
+ "unicorn/prefer-short-escape-sequences": "warn",
232
253
  "unicorn/prefer-simple-condition-first": "warn",
233
254
  "unicorn/prefer-simple-sort-comparator": "warn",
234
- "unicorn/prefer-simplified-conditions": "warn",
255
+ "unicorn/prefer-simplified-conditions": ["warn", { negatedConditions: "expand" }],
235
256
  "unicorn/prefer-single-array-predicate": "warn",
236
257
  "unicorn/prefer-single-call": "warn",
237
258
  "unicorn/prefer-single-object-destructuring": "warn",
@@ -267,6 +288,7 @@ function getUnicornRules(options) {
267
288
  "unicorn/require-number-to-fixed-digits-argument": "warn",
268
289
  "unicorn/require-passive-events": "warn",
269
290
  "unicorn/require-proxy-trap-boolean-return": "error",
291
+ "unicorn/require-text-decoder-streaming": "error",
270
292
  "unicorn/switch-case-braces": "warn",
271
293
  "unicorn/switch-case-break-position": "error",
272
294
  "unicorn/template-indent": "warn",