@icebreakers/eslint-config 2.1.0 → 2.1.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
@@ -10,6 +10,7 @@
10
10
 
11
11
  - Node.js 18 or newer
12
12
  - ESLint 9 with flat config support
13
+ - React related plugins are bundled with this package. Next.js, Query, and other ecosystem presets remain optional and are skipped automatically when their plugins are missing.
13
14
  - Install optional peer plugins when you turn on Tailwind (`eslint-plugin-tailwindcss` or `eslint-plugin-better-tailwindcss`), MDX (`eslint-plugin-mdx`), or UnoCSS (`@unocss/eslint-plugin`)
14
15
 
15
16
  ## Installation
@@ -63,11 +64,11 @@ export default icebreaker({
63
64
 
64
65
  - `miniProgram` – injects Mini Program globals, ignores common outputs/config files, and enables Vue-side Mini Program compatibility tweaks when `vue` is on.
65
66
  - `vue` – enables Vue + optionally version specific overrides (Vue 2/3) and ionic/miniProgram adjustments.
66
- - `react` – defers to the upstream React preset and unlocks accessibility helpers when `a11y` is enabled.
67
- - `query` – toggles the TanStack Query plugin (`@tanstack/eslint-plugin-query`) and its recommended lint rules.
67
+ - `react` – defers to the upstream React preset and unlocks accessibility helpers when `a11y` is enabled. The required React lint plugins are bundled with this package.
68
+ - `query` – toggles the TanStack Query plugin (`@tanstack/eslint-plugin-query`) and its recommended lint rules. Missing plugin installs are treated as a no-op.
68
69
  - `tailwindcss` – pass `true` to use the built-in Tailwind flat config or provide `{ entryPoint, tailwindConfig }` for Tailwind v4/v3 projects.
69
70
  - `mdx` – activates MDX linting via `eslint-plugin-mdx`.
70
- - `a11y` – wires in JSX (React) and Vue accessibility plugins.
71
+ - `a11y` – wires in JSX (React) and Vue accessibility plugins. Missing framework-specific plugins are skipped independently.
71
72
  - `typescript` – extends the TypeScript preset and applies stricter unused diagnostics. Pair with `nestjs` for Nest specific adjustments.
72
73
  - `nestjs` – enables NestJS-centric TypeScript tweaks (empty decorated constructors, declaration merging, DI parameter properties, etc.).
73
74
  - `formatters` – keeps the built-in formatting rules enabled by default.
@@ -197,6 +198,6 @@ You may also pass other flat configs (e.g. from in-house presets) as additional
197
198
 
198
199
  ## Troubleshooting
199
200
 
200
- - Missing plugin errors usually mean the optional dependency is not installed in the current workspace. Add it with `pnpm add -D`.
201
+ - Missing plugin errors usually mean a feature is enabled without its optional dependency being installed in the current workspace. React and Next related presets now auto-skip in that case; other features can be added with `pnpm add -D`.
201
202
  - When combining legacy `.eslintrc` projects, prefer `icebreakerLegacy()` and move overrides into flat config format incrementally.
202
203
  - Tailwind class validation reads from your `tailwind.config.*`; double check the path when using monorepo roots or custom build tooling.
package/README.zh.md CHANGED
@@ -8,6 +8,7 @@
8
8
 
9
9
  - Node.js 18 或更高版本
10
10
  - 支持 Flat Config 的 ESLint 9
11
+ - React 相关插件已随当前包一起分发。Next.js、Query 等生态预设仍保持可选,缺失时会自动跳过对应配置,而不是在解析时直接报错。
11
12
  - 如需启用 Tailwind、MDX、UnoCSS 等,可安装对应的可选依赖:`eslint-plugin-tailwindcss` / `eslint-plugin-better-tailwindcss`、`eslint-plugin-mdx`、`@unocss/eslint-plugin`
12
13
 
13
14
  ## 安装
@@ -61,11 +62,11 @@ export default icebreaker({
61
62
 
62
63
  - `miniProgram`:启用小程序预设,注入全局变量、忽略常见产物/配置文件,并在 `vue: true` 时补充小程序模板兼容调整。
63
64
  - `vue`:启用 Vue 规则,可根据 Vue 2/3 自动切换,并在 `ionic`、`miniProgram` 选项开启时追加对应覆盖。
64
- - `react`:复用上游 React 预设,配合 `a11y` 注入无障碍插件。
65
- - `query`:按需启用 TanStack Query 插件(`@tanstack/eslint-plugin-query`)及其推荐规则。
65
+ - `react`:复用上游 React 预设,配合 `a11y` 注入无障碍插件;所需的 React lint 插件已内置在当前包里。
66
+ - `query`:按需启用 TanStack Query 插件(`@tanstack/eslint-plugin-query`)及其推荐规则;缺少插件时按 no-op 处理。
66
67
  - `tailwindcss`:传入 `true` 使用内置 Tailwind flat 配置,或通过对象指定 Tailwind v4 的入口文件 / v3 的配置文件路径。
67
68
  - `mdx`:激活 `eslint-plugin-mdx` 处理 `.mdx` 文件。
68
- - `a11y`:按需引入 JSX 与 Vue 的无障碍规则。
69
+ - `a11y`:按需引入 JSX 与 Vue 的无障碍规则,缺少某一侧插件时只跳过对应框架配置。
69
70
  - `typescript`:开启 TypeScript 预设,加强未使用诊断,可与 `nestjs` 搭配使用以获得 Nest 专属优化。
70
71
  - `nestjs`:针对 NestJS 场景做 TypeScript 调整(允许带装饰器的空构造函数、依赖注入参数属性、声明合并等)。
71
72
  - `formatters`:默认启用格式化辅助规则。
@@ -198,6 +199,6 @@ export default icebreaker(
198
199
 
199
200
  ## 常见问题
200
201
 
201
- - 如果提示缺少插件,说明当前工作区未安装对应可选依赖,可通过 `pnpm add -D` 补齐。
202
+ - 如果提示缺少插件,通常是某个功能已开启但当前工作区未安装对应可选依赖。React / Next 相关预设会自动跳过;其他能力可通过 `pnpm add -D` 补齐。
202
203
  - 与旧版 `.eslintrc` 混用时建议先改用 `icebreakerLegacy()`,逐步迁移至 Flat Config。
203
204
  - Tailwind 校验依赖 `tailwind.config.*`,Monorepo 或自定义构建路径时请确认配置文件位置。
package/dist/index.cjs CHANGED
@@ -38,6 +38,7 @@ let node_path = require("node:path");
38
38
  node_path = __toESM(node_path);
39
39
  let node_process = require("node:process");
40
40
  node_process = __toESM(node_process);
41
+ let node_url = require("node:url");
41
42
  //#region src/antfu.ts
42
43
  var antfu_exports = /* @__PURE__ */ __exportAll({});
43
44
  __reExport(antfu_exports, require("@antfu/eslint-config"));
@@ -151,27 +152,66 @@ function getDefaultTypescriptOptions(opts) {
151
152
  return { overrides };
152
153
  }
153
154
  //#endregion
155
+ //#region src/utils.ts
156
+ const require$2 = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
157
+ const PACKAGE_DIR = node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
158
+ function isObject(o) {
159
+ return Object.prototype.toString.call(o) === "[object Object]";
160
+ }
161
+ function isPackageAvailable$1(name, searchPaths = [node_process.default.cwd(), PACKAGE_DIR]) {
162
+ try {
163
+ require$2.resolve(name, { paths: searchPaths });
164
+ return true;
165
+ } catch {
166
+ const packageSegments = name.split("/");
167
+ return searchPaths.some((searchPath) => {
168
+ let currentDir = node_path.default.resolve(searchPath);
169
+ while (true) {
170
+ const packageJsonPath = node_path.default.join(currentDir, "node_modules", ...packageSegments, "package.json");
171
+ if (node_fs.default.existsSync(packageJsonPath)) return true;
172
+ const parentDir = node_path.default.dirname(currentDir);
173
+ if (parentDir === currentDir) return false;
174
+ currentDir = parentDir;
175
+ }
176
+ });
177
+ }
178
+ }
179
+ function hasAllPackages(names, searchPaths) {
180
+ return names.every((name) => isPackageAvailable$1(name, searchPaths));
181
+ }
182
+ //#endregion
154
183
  //#region src/features.ts
184
+ const BETTER_TAILWIND_PACKAGES = ["eslint-plugin-better-tailwindcss"];
185
+ const TAILWIND_PACKAGES = ["eslint-plugin-tailwindcss"];
186
+ const STYLELINT_BRIDGE_PACKAGES = ["eslint-plugin-better-stylelint"];
187
+ const MDX_PACKAGES = ["eslint-plugin-mdx"];
188
+ const VUE_A11Y_PACKAGES = ["eslint-plugin-vuejs-accessibility"];
189
+ const REACT_A11Y_PACKAGES = ["eslint-plugin-jsx-a11y"];
190
+ const QUERY_PACKAGES = ["@tanstack/eslint-plugin-query"];
155
191
  function resolveStylelintConfigLoader() {
156
192
  return require("url").pathToFileURL(__filename).href.endsWith(".ts") ? new URL("./stylelint.ts", require("url").pathToFileURL(__filename).href).href : new URL("./stylelint.js", require("url").pathToFileURL(__filename).href).href;
157
193
  }
158
194
  function resolveTailwindPresets(option) {
159
195
  if (!option) return [];
160
- if (typeof option === "object") return [(0, antfu_exports.interopDefault)(import("eslint-plugin-better-tailwindcss")).then((eslintPluginBetterTailwindcss) => {
161
- const betterTailwindcssRules = {
162
- ...eslintPluginBetterTailwindcss.configs["recommended-warn"].rules,
163
- ...eslintPluginBetterTailwindcss.configs["recommended-error"].rules
164
- };
165
- return {
166
- name: "icebreaker/better-tailwindcss",
167
- plugins: { "better-tailwindcss": eslintPluginBetterTailwindcss },
168
- rules: betterTailwindcssRules,
169
- settings: { "better-tailwindcss": {
170
- entryPoint: option.entryPoint,
171
- tailwindConfig: option.tailwindConfig
172
- } }
173
- };
174
- })];
196
+ if (typeof option === "object") {
197
+ if (!hasAllPackages(BETTER_TAILWIND_PACKAGES)) return [];
198
+ return [(0, antfu_exports.interopDefault)(import("eslint-plugin-better-tailwindcss")).then((eslintPluginBetterTailwindcss) => {
199
+ const betterTailwindcssRules = {
200
+ ...eslintPluginBetterTailwindcss.configs["recommended-warn"].rules,
201
+ ...eslintPluginBetterTailwindcss.configs["recommended-error"].rules
202
+ };
203
+ return {
204
+ name: "icebreaker/better-tailwindcss",
205
+ plugins: { "better-tailwindcss": eslintPluginBetterTailwindcss },
206
+ rules: betterTailwindcssRules,
207
+ settings: { "better-tailwindcss": {
208
+ entryPoint: option.entryPoint,
209
+ tailwindConfig: option.tailwindConfig
210
+ } }
211
+ };
212
+ })];
213
+ }
214
+ if (!hasAllPackages(TAILWIND_PACKAGES)) return [];
175
215
  return [(0, antfu_exports.interopDefault)(import("eslint-plugin-tailwindcss")).then((tailwind) => {
176
216
  return tailwind.configs["flat/recommended"];
177
217
  }), { rules: { "tailwindcss/no-custom-classname": "off" } }];
@@ -186,6 +226,7 @@ function resolveStylelintBridgeOptions(option) {
186
226
  }
187
227
  function resolveStylelintBridgePresets(option) {
188
228
  if (!option) return [];
229
+ if (!hasAllPackages(STYLELINT_BRIDGE_PACKAGES)) return [];
189
230
  const pluginModulePromise = import("eslint-plugin-better-stylelint");
190
231
  const stylelintOptions = resolveStylelintBridgeOptions(option);
191
232
  return [
@@ -214,6 +255,7 @@ function resolveStylelintBridgePresets(option) {
214
255
  }
215
256
  function resolveMdxPresets(isEnabled) {
216
257
  if (!isEnabled) return [];
258
+ if (!hasAllPackages(MDX_PACKAGES)) return [];
217
259
  return [(0, antfu_exports.interopDefault)(import("eslint-plugin-mdx")).then((mdx) => {
218
260
  return [{
219
261
  ...mdx.flat,
@@ -230,10 +272,10 @@ function resolveMdxPresets(isEnabled) {
230
272
  function resolveAccessibilityPresets(isEnabled, vueOption, reactOption) {
231
273
  if (!isEnabled) return [];
232
274
  const presets = [];
233
- if (vueOption) presets.push((0, antfu_exports.interopDefault)(import("eslint-plugin-vuejs-accessibility")).then((pluginVueA11y) => {
275
+ if (vueOption && hasAllPackages(VUE_A11Y_PACKAGES)) presets.push((0, antfu_exports.interopDefault)(import("eslint-plugin-vuejs-accessibility")).then((pluginVueA11y) => {
234
276
  return pluginVueA11y.configs["flat/recommended"];
235
277
  }));
236
- if (reactOption) presets.push((0, antfu_exports.interopDefault)(import("eslint-plugin-jsx-a11y")).then((jsxA11y) => {
278
+ if (reactOption && hasAllPackages(REACT_A11Y_PACKAGES)) presets.push((0, antfu_exports.interopDefault)(import("eslint-plugin-jsx-a11y")).then((jsxA11y) => {
237
279
  return jsxA11y.flatConfigs.recommended;
238
280
  }));
239
281
  return presets;
@@ -247,6 +289,7 @@ function resolveNestPresets(isEnabled) {
247
289
  }
248
290
  function resolveQueryPresets(isEnabled) {
249
291
  if (!isEnabled) return [];
292
+ if (!hasAllPackages(QUERY_PACKAGES)) return [];
250
293
  return [(0, antfu_exports.interopDefault)(import("@tanstack/eslint-plugin-query")).then((pluginQuery) => pluginQuery.configs["flat/recommended"])];
251
294
  }
252
295
  //#endregion
@@ -290,11 +333,6 @@ createDefu((object, key, currentValue) => {
290
333
  }
291
334
  });
292
335
  //#endregion
293
- //#region src/utils.ts
294
- function isObject(o) {
295
- return Object.prototype.toString.call(o) === "[object Object]";
296
- }
297
- //#endregion
298
336
  //#region src/options.ts
299
337
  const BASE_DEFAULTS = {
300
338
  formatters: true,
@@ -511,11 +549,27 @@ function getPresets(options, mode) {
511
549
  }
512
550
  //#endregion
513
551
  //#region src/factory.ts
552
+ const OPTIONAL_ANTFU_FEATURE_PACKAGES = {
553
+ react: [
554
+ "@eslint-react/eslint-plugin",
555
+ "eslint-plugin-react-hooks",
556
+ "eslint-plugin-react-refresh"
557
+ ],
558
+ nextjs: ["@next/eslint-plugin-next"]
559
+ };
560
+ function normalizeOptionalAntfuFeatures(options) {
561
+ const normalized = { ...options };
562
+ if (normalized.react && !hasAllPackages([...OPTIONAL_ANTFU_FEATURE_PACKAGES.react])) normalized.react = false;
563
+ if (normalized.nextjs && !hasAllPackages([...OPTIONAL_ANTFU_FEATURE_PACKAGES.nextjs])) normalized.nextjs = false;
564
+ return normalized;
565
+ }
514
566
  function icebreaker(options = {}, ...userConfigs) {
515
- return (0, antfu_exports.antfu)(...getPresets(options), ...userConfigs);
567
+ const [resolved, ...presets] = getPresets(options);
568
+ return (0, antfu_exports.antfu)(normalizeOptionalAntfuFeatures(resolved), ...presets, ...userConfigs);
516
569
  }
517
570
  function icebreakerLegacy(options = {}, ...userConfigs) {
518
- return (0, antfu_exports.antfu)(...getPresets(options, "legacy"), ...userConfigs);
571
+ const [resolved, ...presets] = getPresets(options, "legacy");
572
+ return (0, antfu_exports.antfu)(normalizeOptionalAntfuFeatures(resolved), ...presets, ...userConfigs);
519
573
  }
520
574
  //#endregion
521
575
  exports.__toESM = __toESM;
package/dist/index.d.cts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Awaitable, ConfigNames, OptionsConfig, TypedFlatConfigItem, TypedFlatConfigItem as TypedFlatConfigItem$1 } from "@antfu/eslint-config";
2
+ import { IcebreakerStylelintOptions } from "@icebreakers/stylelint-config";
2
3
 
3
4
  //#region ../../node_modules/.pnpm/@types+json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts
4
5
  // ==================================================================================================
@@ -2956,7 +2957,7 @@ interface TailwindcssOption {
2956
2957
  tailwindConfig?: string;
2957
2958
  }
2958
2959
  type TailwindcssConfig = boolean | TailwindcssOption;
2959
- interface StylelintBridgeOption {
2960
+ interface StylelintBridgeOption extends IcebreakerStylelintOptions {
2960
2961
  cwd?: string;
2961
2962
  }
2962
2963
  type StylelintBridgeConfig = boolean | StylelintBridgeOption;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Awaitable, ConfigNames, OptionsConfig, TypedFlatConfigItem, TypedFlatConfigItem as TypedFlatConfigItem$1 } from "@antfu/eslint-config";
2
+ import { IcebreakerStylelintOptions } from "@icebreakers/stylelint-config";
2
3
 
3
4
  //#region ../../node_modules/.pnpm/@types+json-schema@7.0.15/node_modules/@types/json-schema/index.d.ts
4
5
  // ==================================================================================================
@@ -2956,7 +2957,7 @@ interface TailwindcssOption {
2956
2957
  tailwindConfig?: string;
2957
2958
  }
2958
2959
  type TailwindcssConfig = boolean | TailwindcssOption;
2959
- interface StylelintBridgeOption {
2960
+ interface StylelintBridgeOption extends IcebreakerStylelintOptions {
2960
2961
  cwd?: string;
2961
2962
  }
2962
2963
  type StylelintBridgeConfig = boolean | StylelintBridgeOption;
package/dist/index.js CHANGED
@@ -2,6 +2,7 @@ import { createRequire } from "node:module";
2
2
  import fs from "node:fs";
3
3
  import path from "node:path";
4
4
  import process from "node:process";
5
+ import { fileURLToPath } from "node:url";
5
6
  //#region \0rolldown/runtime.js
6
7
  var __defProp = Object.defineProperty;
7
8
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -142,27 +143,66 @@ function getDefaultTypescriptOptions(opts) {
142
143
  return { overrides };
143
144
  }
144
145
  //#endregion
146
+ //#region src/utils.ts
147
+ const require$1 = createRequire(import.meta.url);
148
+ const PACKAGE_DIR = path.dirname(fileURLToPath(import.meta.url));
149
+ function isObject(o) {
150
+ return Object.prototype.toString.call(o) === "[object Object]";
151
+ }
152
+ function isPackageAvailable$1(name, searchPaths = [process.cwd(), PACKAGE_DIR]) {
153
+ try {
154
+ require$1.resolve(name, { paths: searchPaths });
155
+ return true;
156
+ } catch {
157
+ const packageSegments = name.split("/");
158
+ return searchPaths.some((searchPath) => {
159
+ let currentDir = path.resolve(searchPath);
160
+ while (true) {
161
+ const packageJsonPath = path.join(currentDir, "node_modules", ...packageSegments, "package.json");
162
+ if (fs.existsSync(packageJsonPath)) return true;
163
+ const parentDir = path.dirname(currentDir);
164
+ if (parentDir === currentDir) return false;
165
+ currentDir = parentDir;
166
+ }
167
+ });
168
+ }
169
+ }
170
+ function hasAllPackages(names, searchPaths) {
171
+ return names.every((name) => isPackageAvailable$1(name, searchPaths));
172
+ }
173
+ //#endregion
145
174
  //#region src/features.ts
175
+ const BETTER_TAILWIND_PACKAGES = ["eslint-plugin-better-tailwindcss"];
176
+ const TAILWIND_PACKAGES = ["eslint-plugin-tailwindcss"];
177
+ const STYLELINT_BRIDGE_PACKAGES = ["eslint-plugin-better-stylelint"];
178
+ const MDX_PACKAGES = ["eslint-plugin-mdx"];
179
+ const VUE_A11Y_PACKAGES = ["eslint-plugin-vuejs-accessibility"];
180
+ const REACT_A11Y_PACKAGES = ["eslint-plugin-jsx-a11y"];
181
+ const QUERY_PACKAGES = ["@tanstack/eslint-plugin-query"];
146
182
  function resolveStylelintConfigLoader() {
147
183
  return import.meta.url.endsWith(".ts") ? new URL("./stylelint.ts", import.meta.url).href : new URL("./stylelint.js", import.meta.url).href;
148
184
  }
149
185
  function resolveTailwindPresets(option) {
150
186
  if (!option) return [];
151
- if (typeof option === "object") return [(0, antfu_exports.interopDefault)(import("eslint-plugin-better-tailwindcss")).then((eslintPluginBetterTailwindcss) => {
152
- const betterTailwindcssRules = {
153
- ...eslintPluginBetterTailwindcss.configs["recommended-warn"].rules,
154
- ...eslintPluginBetterTailwindcss.configs["recommended-error"].rules
155
- };
156
- return {
157
- name: "icebreaker/better-tailwindcss",
158
- plugins: { "better-tailwindcss": eslintPluginBetterTailwindcss },
159
- rules: betterTailwindcssRules,
160
- settings: { "better-tailwindcss": {
161
- entryPoint: option.entryPoint,
162
- tailwindConfig: option.tailwindConfig
163
- } }
164
- };
165
- })];
187
+ if (typeof option === "object") {
188
+ if (!hasAllPackages(BETTER_TAILWIND_PACKAGES)) return [];
189
+ return [(0, antfu_exports.interopDefault)(import("eslint-plugin-better-tailwindcss")).then((eslintPluginBetterTailwindcss) => {
190
+ const betterTailwindcssRules = {
191
+ ...eslintPluginBetterTailwindcss.configs["recommended-warn"].rules,
192
+ ...eslintPluginBetterTailwindcss.configs["recommended-error"].rules
193
+ };
194
+ return {
195
+ name: "icebreaker/better-tailwindcss",
196
+ plugins: { "better-tailwindcss": eslintPluginBetterTailwindcss },
197
+ rules: betterTailwindcssRules,
198
+ settings: { "better-tailwindcss": {
199
+ entryPoint: option.entryPoint,
200
+ tailwindConfig: option.tailwindConfig
201
+ } }
202
+ };
203
+ })];
204
+ }
205
+ if (!hasAllPackages(TAILWIND_PACKAGES)) return [];
166
206
  return [(0, antfu_exports.interopDefault)(import("eslint-plugin-tailwindcss")).then((tailwind) => {
167
207
  return tailwind.configs["flat/recommended"];
168
208
  }), { rules: { "tailwindcss/no-custom-classname": "off" } }];
@@ -177,6 +217,7 @@ function resolveStylelintBridgeOptions(option) {
177
217
  }
178
218
  function resolveStylelintBridgePresets(option) {
179
219
  if (!option) return [];
220
+ if (!hasAllPackages(STYLELINT_BRIDGE_PACKAGES)) return [];
180
221
  const pluginModulePromise = import("eslint-plugin-better-stylelint");
181
222
  const stylelintOptions = resolveStylelintBridgeOptions(option);
182
223
  return [
@@ -205,6 +246,7 @@ function resolveStylelintBridgePresets(option) {
205
246
  }
206
247
  function resolveMdxPresets(isEnabled) {
207
248
  if (!isEnabled) return [];
249
+ if (!hasAllPackages(MDX_PACKAGES)) return [];
208
250
  return [(0, antfu_exports.interopDefault)(import("eslint-plugin-mdx")).then((mdx) => {
209
251
  return [{
210
252
  ...mdx.flat,
@@ -221,10 +263,10 @@ function resolveMdxPresets(isEnabled) {
221
263
  function resolveAccessibilityPresets(isEnabled, vueOption, reactOption) {
222
264
  if (!isEnabled) return [];
223
265
  const presets = [];
224
- if (vueOption) presets.push((0, antfu_exports.interopDefault)(import("eslint-plugin-vuejs-accessibility")).then((pluginVueA11y) => {
266
+ if (vueOption && hasAllPackages(VUE_A11Y_PACKAGES)) presets.push((0, antfu_exports.interopDefault)(import("eslint-plugin-vuejs-accessibility")).then((pluginVueA11y) => {
225
267
  return pluginVueA11y.configs["flat/recommended"];
226
268
  }));
227
- if (reactOption) presets.push((0, antfu_exports.interopDefault)(import("eslint-plugin-jsx-a11y")).then((jsxA11y) => {
269
+ if (reactOption && hasAllPackages(REACT_A11Y_PACKAGES)) presets.push((0, antfu_exports.interopDefault)(import("eslint-plugin-jsx-a11y")).then((jsxA11y) => {
228
270
  return jsxA11y.flatConfigs.recommended;
229
271
  }));
230
272
  return presets;
@@ -238,6 +280,7 @@ function resolveNestPresets(isEnabled) {
238
280
  }
239
281
  function resolveQueryPresets(isEnabled) {
240
282
  if (!isEnabled) return [];
283
+ if (!hasAllPackages(QUERY_PACKAGES)) return [];
241
284
  return [(0, antfu_exports.interopDefault)(import("@tanstack/eslint-plugin-query")).then((pluginQuery) => pluginQuery.configs["flat/recommended"])];
242
285
  }
243
286
  //#endregion
@@ -281,11 +324,6 @@ createDefu((object, key, currentValue) => {
281
324
  }
282
325
  });
283
326
  //#endregion
284
- //#region src/utils.ts
285
- function isObject(o) {
286
- return Object.prototype.toString.call(o) === "[object Object]";
287
- }
288
- //#endregion
289
327
  //#region src/options.ts
290
328
  const BASE_DEFAULTS = {
291
329
  formatters: true,
@@ -502,11 +540,27 @@ function getPresets(options, mode) {
502
540
  }
503
541
  //#endregion
504
542
  //#region src/factory.ts
543
+ const OPTIONAL_ANTFU_FEATURE_PACKAGES = {
544
+ react: [
545
+ "@eslint-react/eslint-plugin",
546
+ "eslint-plugin-react-hooks",
547
+ "eslint-plugin-react-refresh"
548
+ ],
549
+ nextjs: ["@next/eslint-plugin-next"]
550
+ };
551
+ function normalizeOptionalAntfuFeatures(options) {
552
+ const normalized = { ...options };
553
+ if (normalized.react && !hasAllPackages([...OPTIONAL_ANTFU_FEATURE_PACKAGES.react])) normalized.react = false;
554
+ if (normalized.nextjs && !hasAllPackages([...OPTIONAL_ANTFU_FEATURE_PACKAGES.nextjs])) normalized.nextjs = false;
555
+ return normalized;
556
+ }
505
557
  function icebreaker(options = {}, ...userConfigs) {
506
- return (0, antfu_exports.antfu)(...getPresets(options), ...userConfigs);
558
+ const [resolved, ...presets] = getPresets(options);
559
+ return (0, antfu_exports.antfu)(normalizeOptionalAntfuFeatures(resolved), ...presets, ...userConfigs);
507
560
  }
508
561
  function icebreakerLegacy(options = {}, ...userConfigs) {
509
- return (0, antfu_exports.antfu)(...getPresets(options, "legacy"), ...userConfigs);
562
+ const [resolved, ...presets] = getPresets(options, "legacy");
563
+ return (0, antfu_exports.antfu)(normalizeOptionalAntfuFeatures(resolved), ...presets, ...userConfigs);
510
564
  }
511
565
  //#endregion
512
566
  export { getPresets, icebreaker, icebreakerLegacy };
package/index.d.ts CHANGED
@@ -4,6 +4,7 @@ import type {
4
4
  OptionsConfig,
5
5
  TypedFlatConfigItem,
6
6
  } from '@antfu/eslint-config'
7
+ import type { IcebreakerStylelintOptions } from '@icebreakers/stylelint-config'
7
8
  import type { Linter } from 'eslint'
8
9
  import type { FlatConfigComposer } from 'eslint-flat-config-utils'
9
10
 
@@ -13,7 +14,7 @@ export interface TailwindcssOption {
13
14
  }
14
15
 
15
16
  export type TailwindcssConfig = boolean | TailwindcssOption
16
- export interface StylelintBridgeOption {
17
+ export interface StylelintBridgeOption extends IcebreakerStylelintOptions {
17
18
  cwd?: string
18
19
  }
19
20
  export type StylelintBridgeConfig = boolean | StylelintBridgeOption
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@icebreakers/eslint-config",
3
3
  "type": "module",
4
- "version": "2.1.0",
4
+ "version": "2.1.2",
5
5
  "description": "ESLint preset from Icebreaker's dev-configs",
6
6
  "author": "ice breaker <1324318532@qq.com>",
7
7
  "license": "MIT",
@@ -48,9 +48,7 @@
48
48
  },
49
49
  "dependencies": {
50
50
  "@antfu/eslint-config": "7.7.3",
51
- "@eslint-react/eslint-plugin": "^3.0.0",
52
- "@next/eslint-plugin-next": "^16.2.1",
53
- "@tanstack/eslint-plugin-query": "^5.95.2",
51
+ "@eslint-react/eslint-plugin": "^2.13.0",
54
52
  "eslint-plugin-better-tailwindcss": "^4.3.2",
55
53
  "eslint-plugin-format": "2.0.1",
56
54
  "eslint-plugin-jsx-a11y": "^6.10.2",
@@ -58,10 +56,12 @@
58
56
  "eslint-plugin-react-refresh": "^0.5.2",
59
57
  "eslint-plugin-tailwindcss": "3.18.2",
60
58
  "eslint-plugin-vuejs-accessibility": "^2.5.0",
61
- "@icebreakers/stylelint-config": "2.2.0",
62
- "eslint-plugin-better-stylelint": "0.1.1"
59
+ "@icebreakers/stylelint-config": "2.2.1",
60
+ "eslint-plugin-better-stylelint": "0.1.2"
63
61
  },
64
62
  "optionalDependencies": {
63
+ "@next/eslint-plugin-next": "^16.2.1",
64
+ "@tanstack/eslint-plugin-query": "^5.95.2",
65
65
  "@unocss/eslint-plugin": "66.6.7",
66
66
  "eslint-plugin-mdx": "3.7.0"
67
67
  },
@@ -72,8 +72,16 @@
72
72
  "tsd": {
73
73
  "directory": "test-d",
74
74
  "compilerOptions": {
75
- "module": "esnext",
76
- "moduleResolution": "bundler",
75
+ "module": "nodenext",
76
+ "baseUrl": ".",
77
+ "paths": {
78
+ "@icebreakers/stylelint-config": [
79
+ "../stylelint/dist/index.d.ts"
80
+ ],
81
+ "eslint-plugin-better-stylelint": [
82
+ "../eslint-plugin-better-stylelint/dist/index.d.ts"
83
+ ]
84
+ },
77
85
  "skipLibCheck": true
78
86
  }
79
87
  },