@icebreakers/eslint-config 3.0.1 → 4.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.
package/dist/index.js CHANGED
@@ -179,8 +179,8 @@ const MDX_PACKAGES = ["eslint-plugin-mdx"];
179
179
  const VUE_A11Y_PACKAGES = ["eslint-plugin-vuejs-accessibility"];
180
180
  const REACT_A11Y_PACKAGES = ["eslint-plugin-jsx-a11y"];
181
181
  const QUERY_PACKAGES = ["@tanstack/eslint-plugin-query"];
182
- function resolveStylelintConfigLoader() {
183
- return import.meta.url.endsWith(".ts") ? new URL("./stylelint.ts", import.meta.url).href : new URL("./stylelint.js", import.meta.url).href;
182
+ function resolveStylelintConfigLoader(moduleUrl = import.meta.url) {
183
+ return moduleUrl.endsWith(".ts") ? new URL("./stylelint.ts", moduleUrl).href : new URL("./stylelint.js", moduleUrl).href;
184
184
  }
185
185
  function resolveTailwindPresets(option) {
186
186
  if (!option) return [];
@@ -284,8 +284,8 @@ function resolveQueryPresets(isEnabled) {
284
284
  return [(0, antfu_exports.interopDefault)(import("@tanstack/eslint-plugin-query")).then((pluginQuery) => pluginQuery.configs["flat/recommended"])];
285
285
  }
286
286
  //#endregion
287
- //#region ../../node_modules/.pnpm/defu@6.1.4/node_modules/defu/dist/defu.mjs
288
- function isPlainObject(value) {
287
+ //#region ../../node_modules/.pnpm/defu@6.1.6/node_modules/defu/dist/defu.mjs
288
+ function isPlainObject$1(value) {
289
289
  if (value === null || typeof value !== "object") return false;
290
290
  const prototype = Object.getPrototypeOf(value);
291
291
  if (prototype !== null && prototype !== Object.prototype && Object.getPrototypeOf(prototype) !== null) return false;
@@ -294,15 +294,15 @@ function isPlainObject(value) {
294
294
  return true;
295
295
  }
296
296
  function _defu(baseObject, defaults, namespace = ".", merger) {
297
- if (!isPlainObject(defaults)) return _defu(baseObject, {}, namespace, merger);
298
- const object = Object.assign({}, defaults);
299
- for (const key in baseObject) {
297
+ if (!isPlainObject$1(defaults)) return _defu(baseObject, {}, namespace, merger);
298
+ const object = { ...defaults };
299
+ for (const key of Object.keys(baseObject)) {
300
300
  if (key === "__proto__" || key === "constructor") continue;
301
301
  const value = baseObject[key];
302
302
  if (value === null || value === void 0) continue;
303
303
  if (merger && merger(object, key, value, namespace)) continue;
304
304
  if (Array.isArray(value) && Array.isArray(object[key])) object[key] = [...value, ...object[key]];
305
- else if (isPlainObject(value) && isPlainObject(object[key])) object[key] = _defu(value, object[key], (namespace ? `${namespace}.` : "") + key.toString(), merger);
305
+ else if (isPlainObject$1(value) && isPlainObject$1(object[key])) object[key] = _defu(value, object[key], (namespace ? `${namespace}.` : "") + key.toString(), merger);
306
306
  else object[key] = value;
307
307
  }
308
308
  return object;
@@ -398,13 +398,14 @@ function isPackageAvailable(name, paths) {
398
398
  }
399
399
  function getDefaultFormatterOptions(cwd = process.cwd()) {
400
400
  const hasXmlPlugin = isPackageAvailable("@prettier/plugin-xml", [ANTFU_PACKAGE_DIR]);
401
+ const hasSlidev = isPackageAvailable("@slidev/cli", [cwd]);
401
402
  return {
402
403
  astro: isPackageAvailable("prettier-plugin-astro", [ANTFU_PACKAGE_DIR]),
403
404
  css: true,
404
405
  graphql: true,
405
406
  html: true,
406
407
  markdown: true,
407
- slidev: isPackageAvailable("@slidev/cli", [cwd]),
408
+ slidev: hasSlidev,
408
409
  svg: hasXmlPlugin,
409
410
  xml: hasXmlPlugin
410
411
  };
@@ -474,11 +475,14 @@ function resolveFormattersOption(input, cwd = process.cwd()) {
474
475
  if (input === false) return false;
475
476
  const defaults = getDefaultFormatterOptions(cwd);
476
477
  const inferredEndOfLine = inferPrettierEndOfLineFromEditorConfig(cwd);
477
- const defaultsWithPrettier = inferredEndOfLine ? defu({ prettierOptions: { endOfLine: inferredEndOfLine } }, defaults) : defaults;
478
- if (input === void 0) return inferredEndOfLine ? defaultsWithPrettier : true;
479
- if (input === true) return defaultsWithPrettier;
480
- if (isObject(input)) return defu(input, defaultsWithPrettier);
481
- return defaultsWithPrettier;
478
+ const defaultsWithFormattingEngines = inferredEndOfLine ? defu({
479
+ oxfmtOptions: { endOfLine: inferredEndOfLine },
480
+ prettierOptions: { endOfLine: inferredEndOfLine }
481
+ }, defaults) : defaults;
482
+ if (input === void 0) return defaultsWithFormattingEngines;
483
+ if (input === true) return defaultsWithFormattingEngines;
484
+ if (isObject(input)) return defu(input, defaultsWithFormattingEngines);
485
+ return defaultsWithFormattingEngines;
482
486
  }
483
487
  function resolveUserOptions(options) {
484
488
  const resolved = defu({}, options ?? {}, BASE_DEFAULTS);
@@ -539,6 +543,29 @@ function getPresets(options, mode) {
539
543
  return [resolved, ...presets];
540
544
  }
541
545
  //#endregion
546
+ //#region src/polyfills.ts
547
+ function createObjectGroupBy() {
548
+ return function groupBy(items, callback) {
549
+ const groups = {};
550
+ let index = 0;
551
+ for (const item of items) {
552
+ const key = callback(item, index++);
553
+ groups[key] ??= [];
554
+ groups[key].push(item);
555
+ }
556
+ return groups;
557
+ };
558
+ }
559
+ function ensureObjectGroupBy() {
560
+ if (typeof Object.groupBy === "function") return;
561
+ Object.defineProperty(Object, "groupBy", {
562
+ value: createObjectGroupBy(),
563
+ configurable: true,
564
+ writable: true
565
+ });
566
+ }
567
+ ensureObjectGroupBy();
568
+ //#endregion
542
569
  //#region src/factory.ts
543
570
  const OPTIONAL_ANTFU_FEATURE_PACKAGES = {
544
571
  react: [
@@ -546,14 +573,74 @@ const OPTIONAL_ANTFU_FEATURE_PACKAGES = {
546
573
  "eslint-plugin-react-hooks",
547
574
  "eslint-plugin-react-refresh"
548
575
  ],
549
- nextjs: ["@next/eslint-plugin-next"]
576
+ nextjs: ["@next/eslint-plugin-next"],
577
+ unocss: ["@unocss/eslint-plugin"]
550
578
  };
579
+ function isPlainObject(value) {
580
+ return value !== null && Object.prototype.toString.call(value) === "[object Object]";
581
+ }
582
+ function cloneUserDefinedOptions(options) {
583
+ const { settings, ...restOptions } = options;
584
+ if (settings === void 0) return { ...restOptions };
585
+ return {
586
+ ...restOptions,
587
+ settings
588
+ };
589
+ }
590
+ function getSettingsRecord(settings) {
591
+ return isPlainObject(settings) ? settings : {};
592
+ }
593
+ function removeNamespacedSetting(options, namespace) {
594
+ if (!isPlainObject(options.settings)) return options;
595
+ const settings = getSettingsRecord(options.settings);
596
+ if (!(namespace in settings)) return options;
597
+ const { [namespace]: _unusedNamespace, ...restSettings } = settings;
598
+ const { settings: _settings, ...restOptions } = options;
599
+ if (Object.keys(restSettings).length === 0) return { ...restOptions };
600
+ return {
601
+ ...restOptions,
602
+ settings: restSettings
603
+ };
604
+ }
551
605
  function normalizeOptionalAntfuFeatures(options) {
552
- const normalized = { ...options };
606
+ const normalized = cloneUserDefinedOptions(options);
553
607
  if (normalized.react && !hasAllPackages([...OPTIONAL_ANTFU_FEATURE_PACKAGES.react])) normalized.react = false;
554
608
  if (normalized.nextjs && !hasAllPackages([...OPTIONAL_ANTFU_FEATURE_PACKAGES.nextjs])) normalized.nextjs = false;
609
+ if (normalized.unocss && !hasAllPackages([...OPTIONAL_ANTFU_FEATURE_PACKAGES.unocss])) {
610
+ normalized.unocss = false;
611
+ return removeNamespacedSetting(normalized, "unocss");
612
+ }
555
613
  return normalized;
556
614
  }
615
+ function mergeNamespacedSetting(options, namespace, value) {
616
+ const currentSettings = getSettingsRecord(options.settings);
617
+ const currentNamespaceSettings = isPlainObject(currentSettings[namespace]) ? currentSettings[namespace] : {};
618
+ return {
619
+ ...options,
620
+ settings: {
621
+ ...currentSettings,
622
+ [namespace]: {
623
+ ...currentNamespaceSettings,
624
+ ...value
625
+ }
626
+ }
627
+ };
628
+ }
629
+ function normalizeUnoCssOptions(options) {
630
+ if (!options.unocss || typeof options.unocss !== "object") return options;
631
+ const { configPath, ...unocssOptions } = options.unocss;
632
+ const { settings, ...restOptions } = options;
633
+ const normalized = settings === void 0 ? {
634
+ ...restOptions,
635
+ unocss: unocssOptions
636
+ } : {
637
+ ...restOptions,
638
+ settings,
639
+ unocss: unocssOptions
640
+ };
641
+ if (!configPath) return normalized;
642
+ return mergeNamespacedSetting(normalized, "unocss", { configPath });
643
+ }
557
644
  function hasGlobalIgnoreShape(config) {
558
645
  const keys = Object.keys(config).filter((key) => key !== "name");
559
646
  return keys.length === 1 && keys[0] === "ignores";
@@ -580,15 +667,73 @@ function normalizeUserConfig(userConfig) {
580
667
  if (typeof userConfig?.then === "function") return Promise.resolve(userConfig).then((resolved) => {
581
668
  return isComposer(resolved) ? resolved : normalizeResolvedUserConfig(resolved);
582
669
  });
583
- return isComposer(userConfig) ? userConfig : normalizeResolvedUserConfig(userConfig);
670
+ const resolvedUserConfig = userConfig;
671
+ return isComposer(resolvedUserConfig) ? resolvedUserConfig : normalizeResolvedUserConfig(resolvedUserConfig);
672
+ }
673
+ function isFormatterOptionsObject(value) {
674
+ return !!value && typeof value === "object" && !Array.isArray(value);
675
+ }
676
+ function toOxfmtRuleEntry(options) {
677
+ return ["error", { ...options ?? {} }];
678
+ }
679
+ function normalizePrettierFormatterForAntfu(formatter) {
680
+ return formatter === "oxfmt" ? true : formatter;
681
+ }
682
+ function normalizeMarkdownFormatterForAntfu(formatter) {
683
+ return formatter === "oxfmt" ? true : formatter;
684
+ }
685
+ function toAntfuOptions(options) {
686
+ const { formatters, ...restOptions } = options;
687
+ if (!isFormatterOptionsObject(formatters)) return restOptions;
688
+ const { oxfmtOptions: _oxfmtOptions, css, html, markdown, graphql, ...restFormatters } = formatters;
689
+ return {
690
+ ...restOptions,
691
+ formatters: {
692
+ ...restFormatters,
693
+ ...css === void 0 ? {} : { css: normalizePrettierFormatterForAntfu(css) },
694
+ ...html === void 0 ? {} : { html: normalizePrettierFormatterForAntfu(html) },
695
+ ...markdown === void 0 ? {} : { markdown: normalizeMarkdownFormatterForAntfu(markdown) },
696
+ ...graphql === void 0 ? {} : { graphql: normalizePrettierFormatterForAntfu(graphql) }
697
+ }
698
+ };
699
+ }
700
+ function applyOxfmtFormatterOverrides(composer, formatters) {
701
+ if (!isFormatterOptionsObject(formatters)) return composer;
702
+ if (formatters.markdown === "oxfmt" && formatters.slidev) throw new Error("`formatters.markdown: \"oxfmt\"` cannot be combined with `formatters.slidev`.");
703
+ const oxfmtOptions = formatters.oxfmtOptions;
704
+ let nextComposer = composer;
705
+ if (formatters.css === "oxfmt") for (const name of [
706
+ "antfu/formatter/css",
707
+ "antfu/formatter/scss",
708
+ "antfu/formatter/less"
709
+ ]) nextComposer = nextComposer.override(name, { rules: {
710
+ "format/oxfmt": toOxfmtRuleEntry(oxfmtOptions),
711
+ "format/prettier": "off"
712
+ } });
713
+ if (formatters.html === "oxfmt") nextComposer = nextComposer.override("antfu/formatter/html", { rules: {
714
+ "format/oxfmt": toOxfmtRuleEntry(oxfmtOptions),
715
+ "format/prettier": "off"
716
+ } });
717
+ if (formatters.markdown === "oxfmt") nextComposer = nextComposer.override("antfu/formatter/markdown", { rules: {
718
+ "format/oxfmt": toOxfmtRuleEntry(oxfmtOptions),
719
+ "format/prettier": "off",
720
+ "format/dprint": "off"
721
+ } });
722
+ if (formatters.graphql === "oxfmt") nextComposer = nextComposer.override("antfu/formatter/graphql", { rules: {
723
+ "format/oxfmt": toOxfmtRuleEntry(oxfmtOptions),
724
+ "format/prettier": "off"
725
+ } });
726
+ return nextComposer;
584
727
  }
585
728
  function icebreaker(options = {}, ...userConfigs) {
586
729
  const [resolved, ...presets] = getPresets(options);
587
- return (0, antfu_exports.antfu)(normalizeOptionalAntfuFeatures(resolved), ...presets, ...userConfigs.map(normalizeUserConfig));
730
+ const normalized = normalizeUnoCssOptions(normalizeOptionalAntfuFeatures(resolved));
731
+ return applyOxfmtFormatterOverrides((0, antfu_exports.antfu)(toAntfuOptions(normalized), ...presets, ...userConfigs.map(normalizeUserConfig)), normalized.formatters);
588
732
  }
589
733
  function icebreakerLegacy(options = {}, ...userConfigs) {
590
734
  const [resolved, ...presets] = getPresets(options, "legacy");
591
- return (0, antfu_exports.antfu)(normalizeOptionalAntfuFeatures(resolved), ...presets, ...userConfigs.map(normalizeUserConfig));
735
+ const normalized = normalizeUnoCssOptions(normalizeOptionalAntfuFeatures(resolved));
736
+ return applyOxfmtFormatterOverrides((0, antfu_exports.antfu)(toAntfuOptions(normalized), ...presets, ...userConfigs.map(normalizeUserConfig)), normalized.formatters);
592
737
  }
593
738
  //#endregion
594
739
  export { getPresets, icebreaker, icebreakerLegacy };
package/index.d.ts CHANGED
@@ -14,14 +14,21 @@ export interface TailwindcssOption {
14
14
  }
15
15
 
16
16
  export type TailwindcssConfig = boolean | TailwindcssOption
17
+ export interface UnocssOption {
18
+ configPath?: string
19
+ attributify?: boolean
20
+ strict?: boolean
21
+ }
22
+ export type UnocssConfig = boolean | UnocssOption
17
23
  export interface StylelintBridgeOption extends IcebreakerStylelintOptions {
18
24
  cwd?: string
19
25
  }
20
26
  export type StylelintBridgeConfig = boolean | StylelintBridgeOption
21
27
 
22
- export type UserDefinedOptions = OptionsConfig & TypedFlatConfigItem & {
28
+ export type UserDefinedOptions = Omit<OptionsConfig, 'unocss'> & TypedFlatConfigItem & {
23
29
  miniProgram?: boolean
24
30
  tailwindcss?: TailwindcssConfig
31
+ unocss?: UnocssConfig
25
32
  stylelint?: StylelintBridgeConfig
26
33
  mdx?: boolean
27
34
  a11y?: boolean
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@icebreakers/eslint-config",
3
3
  "type": "module",
4
- "version": "3.0.1",
4
+ "version": "4.0.1",
5
5
  "description": "ESLint preset from Icebreaker's dev-configs",
6
6
  "author": "ice breaker <1324318532@qq.com>",
7
7
  "license": "MIT",
@@ -39,7 +39,7 @@
39
39
  "index.d.ts"
40
40
  ],
41
41
  "engines": {
42
- "node": ">=22.0.0"
42
+ "node": "^20.19.0 || >=22.12.0"
43
43
  },
44
44
  "peerDependencies": {
45
45
  "eslint-plugin-pnpm": "^1.4.3"
@@ -59,12 +59,12 @@
59
59
  "eslint-plugin-react-refresh": "^0.5.2",
60
60
  "eslint-plugin-tailwindcss": "3.18.2",
61
61
  "eslint-plugin-vuejs-accessibility": "^2.5.0",
62
- "@icebreakers/stylelint-config": "2.2.1",
63
- "eslint-plugin-better-stylelint": "0.1.3"
62
+ "@icebreakers/stylelint-config": "3.0.1",
63
+ "eslint-plugin-better-stylelint": "1.0.0"
64
64
  },
65
65
  "optionalDependencies": {
66
66
  "@next/eslint-plugin-next": "^16.2.2",
67
- "@tanstack/eslint-plugin-query": "^5.96.1",
67
+ "@tanstack/eslint-plugin-query": "^5.96.2",
68
68
  "@unocss/eslint-plugin": "66.6.7",
69
69
  "eslint-plugin-mdx": "3.7.0"
70
70
  },
@@ -91,6 +91,7 @@
91
91
  "scripts": {
92
92
  "dev": "tsdown --watch --sourcemap",
93
93
  "build": "tsdown",
94
+ "bench:formatters": "node --import tsx ./scripts/benchmark-formatters.ts",
94
95
  "test": "vitest run",
95
96
  "test:types": "tsd",
96
97
  "test:dev": "vitest",