@ghettoddos/eslint-config 4.1.1 → 5.0.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/dist/index.mjs CHANGED
@@ -5,18 +5,21 @@ import { fileURLToPath } from "node:url";
5
5
  import fs$1 from "node:fs";
6
6
  import path from "node:path";
7
7
  import { isPackageExists } from "local-pkg";
8
- import createCommand from "eslint-plugin-command/config";
9
8
  import pluginE18e from "@e18e/eslint-plugin";
10
9
  import pluginComments from "@eslint-community/eslint-plugin-eslint-comments";
11
10
  import pluginAntfu from "eslint-plugin-antfu";
11
+ import pluginBaselineJs from "eslint-plugin-baseline-js";
12
+ import pluginDeMorgan from "eslint-plugin-de-morgan";
12
13
  import pluginImportLite from "eslint-plugin-import-lite";
13
14
  import pluginNode from "eslint-plugin-n";
14
15
  import pluginPerfectionist from "eslint-plugin-perfectionist";
15
16
  import pluginUnicorn from "eslint-plugin-unicorn";
16
17
  import pluginUnusedImports from "eslint-plugin-unused-imports";
18
+ import createCommand from "eslint-plugin-command/config";
17
19
  import globals from "globals";
18
20
  import { mergeProcessors, processorPassThrough } from "eslint-merge-processors";
19
21
  import { configs } from "eslint-plugin-regexp";
22
+ import pluginSonarJs from "eslint-plugin-sonarjs";
20
23
  //#region node_modules/.pnpm/find-up-simple@1.0.1/node_modules/find-up-simple/index.js
21
24
  const toPath = (urlOrPath) => urlOrPath instanceof URL ? fileURLToPath(urlOrPath) : urlOrPath;
22
25
  async function findUp(name, { cwd = process.cwd(), type = "file", stopAt } = {}) {
@@ -50,6 +53,26 @@ function findUpSync(name, { cwd = process.cwd(), type = "file", stopAt } = {}) {
50
53
  }
51
54
  }
52
55
  //#endregion
56
+ //#region src/configs/baseline.ts
57
+ async function baseline(options = {}) {
58
+ const { available, baseline, ignoreFeatures = ["functions-caller-arguments"], overrides = {} } = options;
59
+ return [{
60
+ name: "baseline/rules",
61
+ plugins: { "baseline-js": pluginBaselineJs },
62
+ rules: {
63
+ "baseline-js/use-baseline": ["warn", {
64
+ available,
65
+ baseline,
66
+ ignoreFeatures,
67
+ includeJsBuiltins: { preset: "auto" },
68
+ includeWebApis: { preset: "auto" },
69
+ ...options
70
+ }],
71
+ ...overrides
72
+ }
73
+ }];
74
+ }
75
+ //#endregion
53
76
  //#region src/configs/command.ts
54
77
  async function command() {
55
78
  return [{
@@ -72,6 +95,14 @@ async function comments() {
72
95
  }];
73
96
  }
74
97
  //#endregion
98
+ //#region src/configs/de-morgan.ts
99
+ async function deMorgan() {
100
+ return [{
101
+ ...pluginDeMorgan.configs.recommended,
102
+ name: "de-morgan/rules"
103
+ }];
104
+ }
105
+ //#endregion
75
106
  //#region src/globs.ts
76
107
  const GLOB_SRC_EXT = "?([cm])[jt]s?(x)";
77
108
  const GLOB_SRC = "**/*.?([cm])[jt]s?(x)";
@@ -82,6 +113,7 @@ const GLOB_TSX = "**/*.?([cm])tsx";
82
113
  const GLOB_STYLE = "**/*.{c,le,sc}ss";
83
114
  const GLOB_CSS = "**/*.css";
84
115
  const GLOB_POSTCSS = "**/*.{p,post}css";
116
+ const GLOB_LESS = "**/*.less";
85
117
  const GLOB_SCSS = "**/*.scss";
86
118
  const GLOB_JSON = "**/*.json";
87
119
  const GLOB_JSON5 = "**/*.json5";
@@ -94,6 +126,7 @@ const GLOB_TOML = "**/*.toml";
94
126
  const GLOB_XML = "**/*.xml";
95
127
  const GLOB_SVG = "**/*.svg";
96
128
  const GLOB_HTML = "**/*.htm?(l)";
129
+ const GLOB_GRAPHQL = "**/*.{g,graph}ql";
97
130
  const GLOB_MARKDOWN_CODE = `${GLOB_MARKDOWN}/${GLOB_SRC}`;
98
131
  const GLOB_TESTS = [
99
132
  `**/__tests__/**/*.${GLOB_SRC_EXT}`,
@@ -108,6 +141,7 @@ const GLOB_ALL_SRC = [
108
141
  GLOB_JSON,
109
142
  GLOB_JSON5,
110
143
  GLOB_MARKDOWN,
144
+ GLOB_VUE,
111
145
  GLOB_YAML,
112
146
  GLOB_XML,
113
147
  GLOB_HTML
@@ -137,13 +171,17 @@ const GLOB_EXCLUDE = [
137
171
  "**/.output",
138
172
  "**/.vite-inspect",
139
173
  "**/.yarn",
140
- "**/vite.config.*.timestamp-*",
141
174
  "**/CHANGELOG*.md",
142
- "**/*.min.*",
143
175
  "**/LICENSE*",
176
+ "**/*.min.*",
144
177
  "**/__snapshots__",
178
+ "**/vite.config.*.timestamp-*",
145
179
  "**/auto-import?(s).d.ts",
146
- "**/components.d.ts"
180
+ "**/components.d.ts",
181
+ "**/.context",
182
+ "**/.claude",
183
+ "**/.agents",
184
+ "**/.*/skills"
147
185
  ];
148
186
  //#endregion
149
187
  //#region src/configs/disables.ts
@@ -154,10 +192,28 @@ async function disables() {
154
192
  name: "disables/scripts",
155
193
  rules: {
156
194
  "antfu/no-top-level-await": "off",
195
+ "baseline-js/use-baseline": "off",
157
196
  "no-console": "off",
158
197
  "ts/explicit-function-return-type": "off"
159
198
  }
160
199
  },
200
+ {
201
+ files: [`**/cli/${GLOB_SRC}`, `**/cli.${GLOB_SRC_EXT}`],
202
+ name: "disables/cli",
203
+ rules: {
204
+ "antfu/no-top-level-await": "off",
205
+ "baseline-js/use-baseline": "off",
206
+ "no-console": "off"
207
+ }
208
+ },
209
+ {
210
+ files: ["**/bin/**/*", `**/bin.${GLOB_SRC_EXT}`],
211
+ name: "disables/bin",
212
+ rules: {
213
+ "antfu/no-import-dist": "off",
214
+ "antfu/no-import-node-modules-by-path": "off"
215
+ }
216
+ },
161
217
  {
162
218
  files: ["**/*.d.?([cm])ts"],
163
219
  name: "disables/dts",
@@ -171,10 +227,43 @@ async function disables() {
171
227
  files: ["**/*.js", "**/*.cjs"],
172
228
  name: "disables/cjs",
173
229
  rules: { "ts/no-require-imports": "off" }
230
+ },
231
+ {
232
+ files: [`**/*.config.${GLOB_SRC_EXT}`, `**/*.config.*.${GLOB_SRC_EXT}`],
233
+ name: "disables/config-files",
234
+ rules: {
235
+ "antfu/no-top-level-await": "off",
236
+ "baseline-js/use-baseline": "off",
237
+ "no-console": "off",
238
+ "ts/explicit-function-return-type": "off"
239
+ }
174
240
  }
175
241
  ];
176
242
  }
177
243
  //#endregion
244
+ //#region src/configs/e18e.ts
245
+ async function e18e(options = {}) {
246
+ const { isInEditor = false, modernization = true, type = "app", moduleReplacements = type === "lib" && isInEditor, overrides = {}, performanceImprovements = true } = options;
247
+ const configs = pluginE18e.configs;
248
+ return [{
249
+ name: "e18e/rules",
250
+ plugins: { e18e: pluginE18e },
251
+ rules: {
252
+ ...modernization ? { ...configs.modernization.rules } : {},
253
+ ...moduleReplacements ? { ...configs.moduleReplacements.rules } : {},
254
+ ...performanceImprovements ? { ...configs.performanceImprovements.rules } : {},
255
+ ...type === "lib" ? {} : { "e18e/prefer-static-regex": "off" },
256
+ "e18e/prefer-array-at": "off",
257
+ "e18e/prefer-array-from-map": "off",
258
+ "e18e/prefer-array-to-reversed": "off",
259
+ "e18e/prefer-array-to-sorted": "off",
260
+ "e18e/prefer-array-to-spliced": "off",
261
+ "e18e/prefer-spread-syntax": "off",
262
+ ...overrides
263
+ }
264
+ }];
265
+ }
266
+ //#endregion
178
267
  //#region src/utils.ts
179
268
  const scopeUrl = fileURLToPath(new URL(".", import.meta.url));
180
269
  const isCwdInScope = isPackageExists("@ghettoddos/eslint-config");
@@ -198,12 +287,6 @@ const parserPlain = {
198
287
  })
199
288
  };
200
289
  /**
201
- * Combine array and non-array configs into a single array.
202
- */
203
- async function combine(...configs) {
204
- return (await Promise.all(configs)).flat();
205
- }
206
- /**
207
290
  * Rename plugin prefixes in a rule object.
208
291
  * Accepts a map of prefixes to rename.
209
292
  *
@@ -238,7 +321,10 @@ async function ensurePackages(packages) {
238
321
  if (process.env.CI || process.stdout.isTTY === false || isCwdInScope === false) return;
239
322
  const nonExistingPackages = packages.filter((i) => i && !isPackageInScope(i));
240
323
  if (nonExistingPackages.length === 0) return;
241
- if (await (await import("@clack/prompts")).confirm({ message: `${nonExistingPackages.length === 1 ? "Package is" : "Packages are"} required for this config: ${nonExistingPackages.join(", ")}. Do you want to install them?` })) await import("@antfu/install-pkg").then((i) => i.installPackage(nonExistingPackages, { dev: true }));
324
+ const p = await import("@clack/prompts");
325
+ const packagePlural = nonExistingPackages.length === 1 ? "Package is" : "Packages are";
326
+ const pkgs = nonExistingPackages.join(", ");
327
+ if (await p.confirm({ message: `${packagePlural} required for this config: ${pkgs}. Do you want to install them?` })) await import("@antfu/install-pkg").then((i) => i.installPackage(nonExistingPackages, { dev: true }));
242
328
  }
243
329
  function isInEditorEnv() {
244
330
  if (process.env.CI) return false;
@@ -248,27 +334,19 @@ function isInEditorEnv() {
248
334
  function isInGitHooksOrLintStaged() {
249
335
  return !!(process.env.GIT_PARAMS || process.env.VSCODE_GIT_COMMAND || process.env.npm_lifecycle_script?.startsWith("lint-staged"));
250
336
  }
251
- function resolveSubOptions(options, key) {
252
- return typeof options[key] === "boolean" ? {} : options[key] || {};
253
- }
254
- function getOverrides(options, key) {
255
- const sub = resolveSubOptions(options, key);
256
- return {
257
- ...options.overrides?.[key],
258
- ..."overrides" in sub ? sub.overrides : {}
259
- };
260
- }
261
337
  //#endregion
262
338
  //#region src/configs/stylistic.ts
263
339
  const StylisticConfigDefaults = {
264
340
  experimental: false,
265
341
  indent: 2,
266
342
  jsx: true,
343
+ printWidth: 100,
267
344
  quotes: "single",
268
- semi: false
345
+ semi: false,
346
+ tabWidth: 4
269
347
  };
270
348
  async function stylistic(options = {}) {
271
- const { experimental, indent, jsx, overrides = {}, quotes, semi } = {
349
+ const { experimental, indent, jsx, lessOpinionated = false, overrides = {}, printWidth, quotes, semi, tabWidth } = {
272
350
  ...StylisticConfigDefaults,
273
351
  ...options
274
352
  };
@@ -291,13 +369,23 @@ async function stylistic(options = {}) {
291
369
  ...config.rules,
292
370
  ...experimental ? {} : { "antfu/consistent-list-newline": "error" },
293
371
  "antfu/consistent-chaining": "error",
294
- "antfu/curly": "error",
295
- "antfu/if-newline": "error",
296
- "antfu/top-level-function": "error",
372
+ ...lessOpinionated ? { curly: ["error", "all"] } : {
373
+ "antfu/curly": "error",
374
+ "antfu/if-newline": "error",
375
+ "antfu/top-level-function": "error"
376
+ },
297
377
  "style/generator-star-spacing": ["error", {
298
378
  after: true,
299
379
  before: false
300
380
  }],
381
+ "style/max-len": ["warn", {
382
+ code: printWidth,
383
+ ignoreComments: true,
384
+ ignoreRegExpLiterals: true,
385
+ ignoreTrailingComments: true,
386
+ ignoreUrls: true,
387
+ tabWidth: typeof indent === "number" ? indent : indent === "tab" ? tabWidth : 2
388
+ }],
301
389
  "style/yield-star-spacing": ["error", {
302
390
  after: true,
303
391
  before: false
@@ -320,6 +408,7 @@ async function formatters(options = {}, stylistic = {}) {
320
408
  const isPrettierPluginXmlInScope = isPackageInScope("@prettier/plugin-xml");
321
409
  options = {
322
410
  css: true,
411
+ graphql: true,
323
412
  html: true,
324
413
  markdown: true,
325
414
  svg: isPrettierPluginXmlInScope,
@@ -327,13 +416,13 @@ async function formatters(options = {}, stylistic = {}) {
327
416
  };
328
417
  }
329
418
  await ensurePackages(["eslint-plugin-format", options.xml || options.svg ? "@prettier/plugin-xml" : void 0]);
330
- const { indent, quotes, semi } = {
419
+ const { indent, printWidth, quotes, semi } = {
331
420
  ...StylisticConfigDefaults,
332
421
  ...stylistic
333
422
  };
334
423
  const prettierOptions = Object.assign({
335
424
  endOfLine: "auto",
336
- printWidth: 120,
425
+ printWidth: typeof printWidth === "number" ? printWidth : 100,
337
426
  semi,
338
427
  singleQuote: quotes === "single",
339
428
  tabWidth: typeof indent === "number" ? indent : 2,
@@ -360,6 +449,11 @@ async function formatters(options = {}, stylistic = {}) {
360
449
  languageOptions: { parser: parserPlain },
361
450
  name: "formatter/scss",
362
451
  rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "scss" })] }
452
+ }, {
453
+ files: [GLOB_LESS],
454
+ languageOptions: { parser: parserPlain },
455
+ name: "formatter/less",
456
+ rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "less" })] }
363
457
  });
364
458
  if (options.html) configs.push({
365
459
  files: [GLOB_HTML],
@@ -400,6 +494,12 @@ async function formatters(options = {}, stylistic = {}) {
400
494
  parser: "markdown"
401
495
  })] }
402
496
  });
497
+ if (options.graphql) configs.push({
498
+ files: [GLOB_GRAPHQL],
499
+ languageOptions: { parser: parserPlain },
500
+ name: "formatter/graphql",
501
+ rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "graphql" })] }
502
+ });
403
503
  return configs;
404
504
  }
405
505
  //#endregion
@@ -761,37 +861,6 @@ async function jsonc(options = {}) {
761
861
  }];
762
862
  }
763
863
  //#endregion
764
- //#region src/constants.ts
765
- const ReactRefreshAllowConstantExportPackages = ["vite"];
766
- const RemixPackages = [
767
- "@remix-run/node",
768
- "@remix-run/react",
769
- "@remix-run/serve",
770
- "@remix-run/dev"
771
- ];
772
- const ReactRouterPackages = [
773
- "@react-router/node",
774
- "@react-router/react",
775
- "@react-router/serve",
776
- "@react-router/dev"
777
- ];
778
- const NextJsPackages = ["next"];
779
- const ReactNativePackages = ["react-native", "expo"];
780
- const ReactPackages = [
781
- ...RemixPackages,
782
- ...ReactRouterPackages,
783
- ...NextJsPackages,
784
- ...ReactNativePackages,
785
- "react"
786
- ];
787
- const ReactCompilerPackages = ["babel-plugin-react-compiler"];
788
- const VuePackages = [
789
- "vue",
790
- "nuxt",
791
- "vitepress",
792
- "@slidev/cli"
793
- ];
794
- //#endregion
795
864
  //#region src/configs/jsx.ts
796
865
  async function jsx(options = {}) {
797
866
  const { a11y } = options;
@@ -806,13 +875,13 @@ async function jsx(options = {}) {
806
875
  await ensurePackages(["eslint-plugin-jsx-a11y"]);
807
876
  const jsxA11yPlugin = await interopDefault(import("eslint-plugin-jsx-a11y"));
808
877
  const a11yConfig = jsxA11yPlugin.flatConfigs.recommended;
809
- const isUsingNext = NextJsPackages.some((i) => isPackageExists(i));
878
+ const isUsingNext = isPackageExists("next");
810
879
  const a11yRules = {
811
880
  ...a11yConfig.rules || {},
812
- "jsx-a11y/alt-text": ["error", {
881
+ ...isUsingNext ? { "jsx-a11y/alt-text": ["warn", {
813
882
  elements: ["img"],
814
- img: [...isUsingNext ? ["Image"] : []]
815
- }],
883
+ img: ["Image"]
884
+ }] } : {},
816
885
  ...typeof a11y === "object" && a11y.overrides ? a11y.overrides : {}
817
886
  };
818
887
  return [{
@@ -865,21 +934,6 @@ async function markdown(options = {}) {
865
934
  ...overridesMarkdown
866
935
  }
867
936
  },
868
- {
869
- files,
870
- name: "markdown/disables/markdown",
871
- rules: {
872
- "command/command": "off",
873
- "no-irregular-whitespace": "off",
874
- "perfectionist/sort-exports": "off",
875
- "perfectionist/sort-imports": "off",
876
- "regexp/no-legacy-features": "off",
877
- "regexp/no-missing-g-flag": "off",
878
- "regexp/no-useless-dollar-replacements": "off",
879
- "regexp/no-useless-flag": "off",
880
- "style/indent": "off"
881
- }
882
- },
883
937
  {
884
938
  files: [GLOB_MARKDOWN_CODE, ...componentExts.map((ext) => `${GLOB_MARKDOWN}/**/*.${ext}`)],
885
939
  languageOptions: { parserOptions: { ecmaFeatures: { impliedStrict: true } } },
@@ -918,41 +972,32 @@ async function markdown(options = {}) {
918
972
  }
919
973
  //#endregion
920
974
  //#region src/configs/nextjs.ts
975
+ function normalizeRules(rules) {
976
+ return Object.fromEntries(Object.entries(rules).map(([key, value]) => [key, typeof value === "string" ? [value] : value]));
977
+ }
921
978
  async function nextjs(options = {}) {
922
979
  const { files = [GLOB_SRC], overrides = {} } = options;
923
980
  await ensurePackages(["@next/eslint-plugin-next"]);
981
+ const pluginNextJS = await interopDefault(import("@next/eslint-plugin-next"));
982
+ function getRules(name) {
983
+ const rules = pluginNextJS.configs?.[name]?.rules;
984
+ if (!rules) throw new Error(`[@ghettoddos/eslint-config] Failed to find config ${name} in @next/eslint-plugin-next`);
985
+ return normalizeRules(rules);
986
+ }
924
987
  return [{
925
- name: "next/setup",
926
- plugins: { next: await interopDefault(import("@next/eslint-plugin-next")) }
988
+ name: "nextjs/setup",
989
+ plugins: { next: pluginNextJS }
927
990
  }, {
928
991
  files,
929
992
  languageOptions: {
930
993
  parserOptions: { ecmaFeatures: { jsx: true } },
931
994
  sourceType: "module"
932
995
  },
933
- name: "next/rules",
996
+ name: "nextjs/rules",
934
997
  rules: {
935
- "next/google-font-display": "warn",
936
- "next/google-font-preconnect": "warn",
937
- "next/inline-script-id": "error",
938
- "next/next-script-for-ga": "warn",
939
- "next/no-assign-module-variable": "error",
940
- "next/no-async-client-component": "warn",
941
- "next/no-before-interactive-script-outside-document": "warn",
942
- "next/no-css-tags": "warn",
943
- "next/no-document-import-in-page": "error",
944
- "next/no-duplicate-head": "error",
945
- "next/no-head-element": "warn",
946
- "next/no-head-import-in-document": "error",
947
- "next/no-html-link-for-pages": "warn",
948
- "next/no-img-element": "warn",
949
- "next/no-page-custom-font": "warn",
950
- "next/no-script-component-in-head": "error",
951
- "next/no-styled-jsx-in-document": "warn",
952
- "next/no-sync-scripts": "warn",
953
- "next/no-title-in-document-head": "warn",
954
- "next/no-typos": "warn",
955
- "next/no-unwanted-polyfillio": "warn",
998
+ ...getRules("recommended"),
999
+ ...getRules("core-web-vitals"),
1000
+ "node/prefer-global/process": "off",
956
1001
  ...overrides
957
1002
  },
958
1003
  settings: { react: { version: "detect" } }
@@ -1159,41 +1204,87 @@ async function pnpm(options) {
1159
1204
  return configs;
1160
1205
  }
1161
1206
  //#endregion
1207
+ //#region src/configs/prefer-early-return.ts
1208
+ const defaultMaximumStatements = 1;
1209
+ const pluginPreferEarlyReturn = { rules: { "prefer-early-return": {
1210
+ create(context) {
1211
+ const maxStatements = (context.options[0] || { maximumStatements: defaultMaximumStatements }).maximumStatements;
1212
+ function isLonelyIfStatement(statement) {
1213
+ return statement.type === "IfStatement" && statement.alternate == null;
1214
+ }
1215
+ function isOffendingConsequent(consequent) {
1216
+ return consequent.type === "ExpressionStatement" && maxStatements === 0 || consequent.type === "BlockStatement" && consequent.body.length > maxStatements;
1217
+ }
1218
+ function isOffendingIfStatement(statement) {
1219
+ return isLonelyIfStatement(statement) && isOffendingConsequent(statement.consequent);
1220
+ }
1221
+ function hasSimplifiableConditionalBody(functionBody) {
1222
+ const body = functionBody.body;
1223
+ return functionBody.type === "BlockStatement" && body.length === 1 && isOffendingIfStatement(body[0]);
1224
+ }
1225
+ function checkFunctionBody(functionNode) {
1226
+ const body = functionNode.body;
1227
+ if (hasSimplifiableConditionalBody(body)) context.report(body, "Prefer an early return to a conditionally-wrapped function body");
1228
+ }
1229
+ return {
1230
+ ArrowFunctionExpression: checkFunctionBody,
1231
+ FunctionDeclaration: checkFunctionBody,
1232
+ FunctionExpression: checkFunctionBody
1233
+ };
1234
+ },
1235
+ meta: {
1236
+ docs: {
1237
+ category: "Best Practices",
1238
+ description: "Prefer early returns over full-body conditional wrapping in function declarations.",
1239
+ recommended: false,
1240
+ uri: "https://github.com/Shopify/web-configs/blob/main/packages/eslint-plugin/docs/rules/prefer-early-return.md"
1241
+ },
1242
+ schema: [{
1243
+ additionalProperties: false,
1244
+ properties: { maximumStatements: { type: "integer" } },
1245
+ type: "object"
1246
+ }]
1247
+ }
1248
+ } } };
1249
+ async function preferEarlyReturn() {
1250
+ return [{
1251
+ name: "prefer-early-return/rules",
1252
+ plugins: { "prefer-early-return": pluginPreferEarlyReturn },
1253
+ rules: { "prefer-early-return/prefer-early-return": "error" }
1254
+ }];
1255
+ }
1256
+ //#endregion
1162
1257
  //#region src/configs/react.ts
1258
+ const ReactRefreshAllowConstantExportPackages = ["vite"];
1259
+ const RemixPackages = [
1260
+ "@remix-run/node",
1261
+ "@remix-run/react",
1262
+ "@remix-run/serve",
1263
+ "@remix-run/dev"
1264
+ ];
1265
+ const ReactRouterPackages = [
1266
+ "@react-router/node",
1267
+ "@react-router/react",
1268
+ "@react-router/serve",
1269
+ "@react-router/dev"
1270
+ ];
1271
+ const NextJsPackages = ["next"];
1163
1272
  async function react(options = {}) {
1164
- const { files = [GLOB_SRC], filesTypeAware = [GLOB_TS, GLOB_TSX], ignoresTypeAware = [`${GLOB_MARKDOWN}/**`], overrides = {}, tsconfigPath, reactCompiler = ReactCompilerPackages.some((i) => isPackageExists(i)) } = options;
1165
- await ensurePackages([
1166
- "@eslint-react/eslint-plugin",
1167
- "eslint-plugin-react-hooks",
1168
- "eslint-plugin-react-refresh"
1169
- ]);
1273
+ const { files = [GLOB_SRC], filesTypeAware = [GLOB_TS, GLOB_TSX], ignoresTypeAware = [`${GLOB_MARKDOWN}/**`], overrides = {}, tsconfigPath } = options;
1274
+ await ensurePackages(["@eslint-react/eslint-plugin", "eslint-plugin-react-refresh"]);
1170
1275
  const isTypeAware = !!tsconfigPath;
1171
- const typeAwareRules = {
1172
- "react/no-leaked-conditional-rendering": "warn",
1173
- "react/no-implicit-key": "error"
1174
- };
1175
- const [pluginReact, pluginReactHooks, pluginReactRefresh] = await Promise.all([
1176
- interopDefault(import("@eslint-react/eslint-plugin")),
1177
- interopDefault(import("eslint-plugin-react-hooks")),
1178
- interopDefault(import("eslint-plugin-react-refresh"))
1179
- ]);
1276
+ const typeAwareRules = { "react/no-leaked-conditional-rendering": "error" };
1277
+ const [pluginReact, pluginReactRefresh] = await Promise.all([interopDefault(import("@eslint-react/eslint-plugin")), interopDefault(import("eslint-plugin-react-refresh"))]);
1180
1278
  const isAllowConstantExport = ReactRefreshAllowConstantExportPackages.some((i) => isPackageExists(i));
1181
1279
  const isUsingRemix = RemixPackages.some((i) => isPackageExists(i));
1182
1280
  const isUsingReactRouter = ReactRouterPackages.some((i) => isPackageExists(i));
1183
1281
  const isUsingNext = NextJsPackages.some((i) => isPackageExists(i));
1184
- const plugins = pluginReact.configs.all.plugins;
1185
1282
  return [
1186
1283
  {
1187
1284
  name: "react/setup",
1188
1285
  plugins: {
1189
- "react": plugins["@eslint-react"],
1190
- "react-dom": plugins["@eslint-react/dom"],
1191
- "react-hooks": pluginReactHooks,
1192
- "react-hooks-extra": plugins["@eslint-react/hooks-extra"],
1193
- "react-naming-convention": plugins["@eslint-react/naming-convention"],
1194
- "react-refresh": pluginReactRefresh,
1195
- "react-rsc": plugins["@eslint-react/rsc"],
1196
- "react-web-api": plugins["@eslint-react/web-api"]
1286
+ "react": pluginReact.configs.all.plugins["@eslint-react"],
1287
+ "react-refresh": pluginReactRefresh
1197
1288
  }
1198
1289
  },
1199
1290
  {
@@ -1204,89 +1295,7 @@ async function react(options = {}) {
1204
1295
  },
1205
1296
  name: "react/rules",
1206
1297
  rules: {
1207
- "react/jsx-key-before-spread": "warn",
1208
- "react/jsx-no-comment-textnodes": "warn",
1209
- "react/jsx-no-duplicate-props": "warn",
1210
- "react/jsx-uses-react": "warn",
1211
- "react/jsx-uses-vars": "warn",
1212
- "react/no-access-state-in-setstate": "error",
1213
- "react/no-array-index-key": "warn",
1214
- "react/no-children-count": "warn",
1215
- "react/no-children-for-each": "warn",
1216
- "react/no-children-map": "warn",
1217
- "react/no-children-only": "warn",
1218
- "react/no-children-to-array": "warn",
1219
- "react/no-clone-element": "warn",
1220
- "react/no-component-will-mount": "error",
1221
- "react/no-component-will-receive-props": "error",
1222
- "react/no-component-will-update": "error",
1223
- "react/no-context-provider": "warn",
1224
- "react/no-create-ref": "error",
1225
- "react/no-default-props": "error",
1226
- "react/no-direct-mutation-state": "error",
1227
- "react/no-forward-ref": "warn",
1228
- "react/no-missing-key": "error",
1229
- "react/no-nested-component-definitions": "error",
1230
- "react/no-nested-lazy-component-declarations": "error",
1231
- "react/no-prop-types": "error",
1232
- "react/no-redundant-should-component-update": "error",
1233
- "react/no-set-state-in-component-did-mount": "warn",
1234
- "react/no-set-state-in-component-did-update": "warn",
1235
- "react/no-set-state-in-component-will-update": "warn",
1236
- "react/no-string-refs": "error",
1237
- "react/no-unnecessary-use-prefix": "warn",
1238
- "react/no-unsafe-component-will-mount": "warn",
1239
- "react/no-unsafe-component-will-receive-props": "warn",
1240
- "react/no-unsafe-component-will-update": "warn",
1241
- "react/no-unused-class-component-members": "warn",
1242
- "react/no-use-context": "warn",
1243
- "react/no-useless-forward-ref": "warn",
1244
- "react/prefer-use-state-lazy-initialization": "warn",
1245
- "react/prefer-namespace-import": "error",
1246
- "react/jsx-shorthand-boolean": "warn",
1247
- "react/prefer-destructuring-assignment": "warn",
1248
- "react/no-missing-context-display-name": "warn",
1249
- "react/no-missing-component-display-name": "warn",
1250
- "react-rsc/function-definition": "error",
1251
- "react-dom/no-dangerously-set-innerhtml": "warn",
1252
- "react-dom/no-dangerously-set-innerhtml-with-children": "error",
1253
- "react-dom/no-find-dom-node": "error",
1254
- "react-dom/no-flush-sync": "error",
1255
- "react-dom/no-hydrate": "error",
1256
- "react-dom/no-namespace": "error",
1257
- "react-dom/no-render": "error",
1258
- "react-dom/no-render-return-value": "error",
1259
- "react-dom/no-script-url": "warn",
1260
- "react-dom/no-unsafe-iframe-sandbox": "warn",
1261
- "react-dom/no-use-form-state": "error",
1262
- "react-dom/no-void-elements-with-children": "error",
1263
- "react-hooks-extra/no-direct-set-state-in-use-effect": "warn",
1264
- "react-naming-convention/context-name": "warn",
1265
- "react-naming-convention/ref-name": "warn",
1266
- "react-naming-convention/use-state": "warn",
1267
- "react-web-api/no-leaked-event-listener": "warn",
1268
- "react-web-api/no-leaked-interval": "warn",
1269
- "react-web-api/no-leaked-resize-observer": "warn",
1270
- "react-web-api/no-leaked-timeout": "warn",
1271
- "react-hooks/rules-of-hooks": "error",
1272
- "react-hooks/exhaustive-deps": "warn",
1273
- ...reactCompiler ? {
1274
- "react-hooks/config": "error",
1275
- "react-hooks/error-boundaries": "error",
1276
- "react-hooks/component-hook-factories": "error",
1277
- "react-hooks/gating": "error",
1278
- "react-hooks/globals": "error",
1279
- "react-hooks/immutability": "error",
1280
- "react-hooks/preserve-manual-memoization": "error",
1281
- "react-hooks/purity": "error",
1282
- "react-hooks/refs": "error",
1283
- "react-hooks/set-state-in-effect": "error",
1284
- "react-hooks/set-state-in-render": "error",
1285
- "react-hooks/static-components": "error",
1286
- "react-hooks/unsupported-syntax": "warn",
1287
- "react-hooks/use-memo": "error",
1288
- "react-hooks/incompatible-library": "warn"
1289
- } : {},
1298
+ ...pluginReact.configs.recommended.rules,
1290
1299
  "react-refresh/only-export-components": ["error", {
1291
1300
  allowConstantExport: isAllowConstantExport,
1292
1301
  allowExportNames: [...isUsingNext ? [
@@ -1323,12 +1332,8 @@ async function react(options = {}) {
1323
1332
  files: filesTypeAware,
1324
1333
  name: "react/typescript",
1325
1334
  rules: {
1326
- "react-dom/no-string-style-prop": "off",
1327
- "react-dom/no-unknown-property": "off",
1328
- "react/jsx-no-duplicate-props": "off",
1329
- "react/jsx-no-undef": "off",
1330
- "react/jsx-uses-react": "off",
1331
- "react/jsx-uses-vars": "off"
1335
+ "react/dom-no-string-style-prop": "off",
1336
+ "react/dom-no-unknown-property": "off"
1332
1337
  }
1333
1338
  },
1334
1339
  ...isTypeAware ? [{
@@ -1340,71 +1345,6 @@ async function react(options = {}) {
1340
1345
  ];
1341
1346
  }
1342
1347
  //#endregion
1343
- //#region src/configs/react-native.ts
1344
- async function reactNative(options = {}) {
1345
- const { expo = isPackageExists("expo"), files = [GLOB_SRC], overrides = {} } = options;
1346
- await ensurePackages([
1347
- "@react-native/eslint-plugin",
1348
- "eslint-plugin-react-native",
1349
- ...expo ? ["eslint-plugin-expo"] : []
1350
- ]);
1351
- const [pluginReactNative, pluginReactNativeCommunity, pluginExpo] = await Promise.all([
1352
- interopDefault(import("@react-native/eslint-plugin")),
1353
- interopDefault(import("eslint-plugin-react-native")),
1354
- ...expo ? [interopDefault(import("eslint-plugin-expo"))] : []
1355
- ]);
1356
- return [{
1357
- name: "react-native/setup",
1358
- plugins: {
1359
- "react-native": pluginReactNative,
1360
- "react-native-community": pluginReactNativeCommunity,
1361
- ...expo ? { expo: pluginExpo } : {}
1362
- }
1363
- }, {
1364
- files,
1365
- languageOptions: {
1366
- globals: {
1367
- ...globals.browser,
1368
- "__DEV__": "readonly",
1369
- "alert": false,
1370
- "cancelAnimationFrame": false,
1371
- "cancelIdleCallback": false,
1372
- "clearImmediate": false,
1373
- "ErrorUtils": false,
1374
- "fetch": false,
1375
- "FormData": false,
1376
- "navigator": false,
1377
- "process": false,
1378
- "requestAnimationFrame": false,
1379
- "requestIdleCallback": false,
1380
- "setImmediate": false,
1381
- "shared-node-browser": true,
1382
- "window": false,
1383
- "XMLHttpRequest": false
1384
- },
1385
- parserOptions: { ecmaFeatures: { jsx: true } },
1386
- sourceType: "module"
1387
- },
1388
- name: "react-native/rules",
1389
- rules: {
1390
- "node/prefer-global/process": "off",
1391
- "react-native-community/no-inline-styles": "warn",
1392
- "react-native-community/no-raw-text": "warn",
1393
- "react-native-community/no-single-element-style-arrays": "warn",
1394
- "react-native-community/no-unused-styles": "warn",
1395
- "react-native/no-deep-imports": "error",
1396
- "ts/no-require-imports": ["warn", { allow: ["\\.(aac|aiff|avif|bmp|caf|db|gif|heic|html|jpeg|jpg|json|m4a|m4v|mov|mp3|mp4|mpeg|mpg|otf|pdf|png|psd|svg|ttf|wav|webm|webp|xml|yaml|yml|zip)$"] }],
1397
- ...expo ? {
1398
- "expo/no-dynamic-env-var": "error",
1399
- "expo/no-env-var-destructuring": "error",
1400
- "expo/use-dom-exports": "error"
1401
- } : {},
1402
- ...overrides
1403
- },
1404
- settings: { react: { version: "detect" } }
1405
- }];
1406
- }
1407
- //#endregion
1408
1348
  //#region src/configs/regexp.ts
1409
1349
  async function regexp(options = {}) {
1410
1350
  const config = configs["flat/recommended"];
@@ -1422,6 +1362,18 @@ async function regexp(options = {}) {
1422
1362
  }];
1423
1363
  }
1424
1364
  //#endregion
1365
+ //#region src/configs/sonarjs.ts
1366
+ async function sonarjs(options = {}) {
1367
+ return [{
1368
+ name: "sonarjs/rules",
1369
+ plugins: { sonarjs: pluginSonarJs },
1370
+ rules: {
1371
+ ...pluginSonarJs.configs.recommended.rules,
1372
+ ...options.overrides
1373
+ }
1374
+ }];
1375
+ }
1376
+ //#endregion
1425
1377
  //#region src/configs/sort.ts
1426
1378
  /**
1427
1379
  * Sort package.json
@@ -1656,29 +1608,63 @@ function sortTsconfig() {
1656
1608
  }
1657
1609
  //#endregion
1658
1610
  //#region src/configs/tailwindcss.ts
1659
- async function tailwindcss(options = {}) {
1660
- const { entryPoint, overrides = {}, stylistic = true, tsconfigPath } = options;
1611
+ let _pluginTailwindCSS;
1612
+ async function tailwindcss(options) {
1613
+ const { detectComponentClasses, entryPoint, overrides = {}, rootFontSize, selectors, stylistic = true, tsconfigPath } = options;
1661
1614
  await ensurePackages(["eslint-plugin-better-tailwindcss"]);
1662
1615
  const [pluginTailwindCSS] = await Promise.all([interopDefault(import("eslint-plugin-better-tailwindcss"))]);
1663
- const { indent = 2 } = typeof stylistic === "boolean" ? {} : stylistic;
1616
+ _pluginTailwindCSS = _pluginTailwindCSS || {
1617
+ ...pluginTailwindCSS,
1618
+ rules: {
1619
+ ...pluginTailwindCSS.rules,
1620
+ "multiline-classname": {
1621
+ create(context) {
1622
+ return { JSXAttribute(node) {
1623
+ if (node.name?.type !== "JSXIdentifier") return;
1624
+ if (node.name.name !== "className") return;
1625
+ if (node.value?.type === "Literal" && typeof node.value.value === "string" && node.value.value.includes("\n")) {
1626
+ const raw = node.value.value;
1627
+ context.report({
1628
+ fix(fixer) {
1629
+ const escaped = raw.replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
1630
+ return fixer.replaceText(node.value, `{\`${escaped}\`}`);
1631
+ },
1632
+ message: "Multiline className strings can cause hydration errors. Use a template literal/expression instead.",
1633
+ node: node.value
1634
+ });
1635
+ }
1636
+ } };
1637
+ },
1638
+ meta: {
1639
+ fixable: "code",
1640
+ schema: [],
1641
+ type: "suggestion"
1642
+ }
1643
+ }
1644
+ }
1645
+ };
1646
+ const { indent = 2, printWidth = 100, tabWidth = 4 } = typeof stylistic === "boolean" ? {} : stylistic;
1664
1647
  return [{
1665
1648
  name: "tailwindcss",
1666
- plugins: { tailwindcss: pluginTailwindCSS },
1649
+ plugins: { "better-tailwindcss": _pluginTailwindCSS },
1667
1650
  rules: {
1668
1651
  ...stylistic ? {
1669
- "tailwindcss/enforce-canonical-classes": "warn",
1670
- "tailwindcss/enforce-consistent-class-order": "warn",
1671
- "tailwindcss/enforce-consistent-line-wrapping": ["warn", { indent: typeof indent === "number" ? indent : indent === "tab" ? "tab" : 2 }],
1672
- "tailwindcss/no-deprecated-classes": "warn",
1673
- "tailwindcss/no-duplicate-classes": "warn",
1674
- "tailwindcss/no-unnecessary-whitespace": "warn"
1652
+ ...pluginTailwindCSS.configs.stylistic.rules,
1653
+ "better-tailwindcss/enforce-consistent-line-wrapping": ["warn", {
1654
+ indent: typeof indent === "number" ? indent : indent === "tab" ? "tab" : 2,
1655
+ printWidth,
1656
+ tabWidth: typeof indent === "number" ? indent : indent === "tab" ? tabWidth : 2
1657
+ }],
1658
+ "better-tailwindcss/multiline-classname": "error"
1675
1659
  } : {},
1676
- "tailwindcss/no-conflicting-classes": "error",
1677
- "tailwindcss/no-unknown-classes": "error",
1660
+ ...pluginTailwindCSS.configs.correctness.rules,
1678
1661
  ...overrides
1679
1662
  },
1680
1663
  settings: { "better-tailwindcss": {
1664
+ detectComponentClasses,
1681
1665
  entryPoint,
1666
+ rootFontSize,
1667
+ selectors,
1682
1668
  tsconfig: tsconfigPath
1683
1669
  } }
1684
1670
  }];
@@ -1713,6 +1699,7 @@ async function test(options = {}) {
1713
1699
  "test/prefer-hooks-in-order": "error",
1714
1700
  "test/prefer-lowercase-title": "error",
1715
1701
  "antfu/no-top-level-await": "off",
1702
+ "baseline-js/use-baseline": "off",
1716
1703
  "e18e/prefer-static-regex": "off",
1717
1704
  "no-unused-expressions": "off",
1718
1705
  "node/prefer-global/process": "off",
@@ -1893,8 +1880,8 @@ async function typescript(options = {}) {
1893
1880
  }
1894
1881
  }] : [],
1895
1882
  ...erasableOnly ? [{
1896
- name: "antfu/typescript/erasable-syntax-only",
1897
- plugins: { "erasable-syntax-only": await interopDefault(import("./lib-C63e_zBF.mjs")) },
1883
+ name: "typescript/erasable-syntax-only",
1884
+ plugins: { "erasable-syntax-only": await interopDefault(import("./lib-C1Uxp5ZW.mjs")) },
1898
1885
  rules: {
1899
1886
  "erasable-syntax-only/enums": "error",
1900
1887
  "erasable-syntax-only/import-aliases": "error",
@@ -1956,11 +1943,6 @@ async function vue(options = {}) {
1956
1943
  const { a11y = false, files = [GLOB_VUE], overrides = {}, stylistic = true, vueVersion = 3 } = options;
1957
1944
  const sfcBlocks = options.sfcBlocks === true ? {} : options.sfcBlocks ?? {};
1958
1945
  const { indent = 2 } = typeof stylistic === "boolean" ? {} : stylistic;
1959
- await ensurePackages([
1960
- "eslint-plugin-vue",
1961
- "vue-eslint-parser",
1962
- "eslint-processor-vue-blocks"
1963
- ]);
1964
1946
  if (a11y) await ensurePackages(["eslint-plugin-vuejs-accessibility"]);
1965
1947
  const [pluginVue, parserVue, processorVueBlocks, pluginVueA11y] = await Promise.all([
1966
1948
  interopDefault(import("eslint-plugin-vue")),
@@ -2203,22 +2185,6 @@ async function yaml(options = {}) {
2203
2185
  }];
2204
2186
  }
2205
2187
  //#endregion
2206
- //#region src/configs/e18e.ts
2207
- async function e18e(options = {}) {
2208
- const { isInEditor = false, modernization = true, type = "app", moduleReplacements = type === "lib" && isInEditor, overrides = {}, performanceImprovements = true } = options;
2209
- const configs = pluginE18e.configs;
2210
- return [{
2211
- name: "antfu/e18e/rules",
2212
- plugins: { e18e: pluginE18e },
2213
- rules: {
2214
- ...modernization ? { ...configs.modernization.rules } : {},
2215
- ...moduleReplacements ? { ...configs.moduleReplacements.rules } : {},
2216
- ...performanceImprovements ? { ...configs.performanceImprovements.rules } : {},
2217
- ...overrides
2218
- }
2219
- }];
2220
- }
2221
- //#endregion
2222
2188
  //#region src/factory.ts
2223
2189
  const flatConfigProps = [
2224
2190
  "name",
@@ -2229,15 +2195,17 @@ const flatConfigProps = [
2229
2195
  "rules",
2230
2196
  "settings"
2231
2197
  ];
2198
+ const VuePackages = [
2199
+ "vue",
2200
+ "nuxt",
2201
+ "vitepress",
2202
+ "@slidev/cli"
2203
+ ];
2232
2204
  const defaultPluginRenaming = {
2233
2205
  "@eslint-react": "react",
2234
- "@eslint-react/dom": "react-dom",
2235
- "@eslint-react/hooks-extra": "react-hooks-extra",
2236
- "@eslint-react/naming-convention": "react-naming-convention",
2237
2206
  "@next/next": "next",
2238
2207
  "@stylistic": "style",
2239
2208
  "@typescript-eslint": "ts",
2240
- "better-tailwindcss": "tailwindcss",
2241
2209
  "import-lite": "import",
2242
2210
  "n": "node",
2243
2211
  "vitest": "test",
@@ -2254,7 +2222,7 @@ const defaultPluginRenaming = {
2254
2222
  * The merged ESLint configurations.
2255
2223
  */
2256
2224
  function config(options = {}, ...userConfigs) {
2257
- const { autoRenamePlugins = true, componentExts = [], e18e: enableE18e = true, gitignore: enableGitignore = true, ignores: userIgnores = [], imports: enableImports = true, jsdoc: enableJsdoc = true, jsx: enableJsx = true, nextjs: enableNext = NextJsPackages.some((i) => isPackageExists(i)), node: enableNode = true, pnpm: enableCatalogs = !!findUpSync("pnpm-workspace.yaml"), react: enableReact = ReactPackages.some((i) => isPackageExists(i)), reactNative: enableReactNative = ReactNativePackages.some((i) => isPackageExists(i)), regexp: enableRegexp = true, tailwindcss: enableTailwindCSS = isPackageExists("tailwindcss"), type: appType = "app", typescript: enableTypeScript = isPackageExists("typescript") || isPackageExists("@typescript/native-preview"), unicorn: enableUnicorn = true, unocss: enableUnoCSS = isPackageExists("unocss"), vue: enableVue = VuePackages.some((i) => isPackageExists(i)) } = options;
2225
+ const { autoRenamePlugins = true, baseline: enableBaseLineJs = false, componentExts = [], e18e: enableE18e = true, gitignore: enableGitignore = true, ignores: userIgnores = [], imports: enableImports = true, jsdoc: enableJsdoc = true, jsx: enableJsx = true, nextjs: enableNextjs = isPackageExists("next"), node: enableNode = true, pnpm: enableCatalogs = !!findUpSync("pnpm-workspace.yaml"), react: enableReact = false, regexp: enableRegexp = true, sonarjs: enableSonarJs = false, tailwindcss: enableTailwindCSS = isPackageExists("tailwindcss"), type: appType = "app", typescript: enableTypeScript = isPackageExists("typescript") || isPackageExists("@typescript/native-preview"), unicorn: enableUnicorn = true, unocss: enableUnoCSS = false, vue: enableVue = VuePackages.some((i) => isPackageExists(i)) } = options;
2258
2226
  let isInEditor = options.isInEditor;
2259
2227
  if (isInEditor == null) {
2260
2228
  isInEditor = isInEditorEnv();
@@ -2276,17 +2244,19 @@ function config(options = {}, ...userConfigs) {
2276
2244
  configs.push(ignores(userIgnores, !enableTypeScript), javascript({
2277
2245
  isInEditor,
2278
2246
  overrides: getOverrides(options, "javascript")
2279
- }), comments(), command(), perfectionist());
2247
+ }), comments(), command(), deMorgan(), preferEarlyReturn(), perfectionist());
2280
2248
  if (enableNode) configs.push(node());
2281
2249
  if (enableJsdoc) configs.push(jsdoc({ stylistic: stylisticOptions }));
2282
2250
  if (enableImports) configs.push(imports({
2283
2251
  stylistic: stylisticOptions,
2284
2252
  ...resolveSubOptions(options, "imports")
2285
2253
  }));
2254
+ if (enableBaseLineJs) configs.push(baseline({ ...resolveSubOptions(options, "baseline") }));
2286
2255
  if (enableE18e) configs.push(e18e({
2287
2256
  isInEditor,
2288
2257
  ...enableE18e === true ? {} : enableE18e
2289
2258
  }));
2259
+ if (enableSonarJs) configs.push(sonarjs({ ...resolveSubOptions(options, "sonarjs") }));
2290
2260
  if (enableUnicorn) configs.push(unicorn(enableUnicorn === true ? {} : enableUnicorn));
2291
2261
  if (enableVue) componentExts.push("vue");
2292
2262
  if (enableJsx) configs.push(jsx(enableJsx === true ? {} : enableJsx));
@@ -2298,6 +2268,7 @@ function config(options = {}, ...userConfigs) {
2298
2268
  }));
2299
2269
  if (stylisticOptions) configs.push(stylistic({
2300
2270
  ...stylisticOptions,
2271
+ lessOpinionated: options.lessOpinionated,
2301
2272
  overrides: getOverrides(options, "stylistic")
2302
2273
  }));
2303
2274
  if (enableRegexp) configs.push(regexp(typeof enableRegexp === "boolean" ? {} : enableRegexp));
@@ -2317,11 +2288,7 @@ function config(options = {}, ...userConfigs) {
2317
2288
  overrides: getOverrides(options, "react"),
2318
2289
  tsconfigPath
2319
2290
  }));
2320
- if (enableReactNative) configs.push(reactNative({
2321
- ...resolveSubOptions(options, "reactNative"),
2322
- overrides: getOverrides(options, "reactNative")
2323
- }));
2324
- if (enableNext) configs.push(nextjs({ overrides: getOverrides(options, "nextjs") }));
2291
+ if (enableNextjs) configs.push(nextjs({ overrides: getOverrides(options, "nextjs") }));
2325
2292
  if (enableUnoCSS) configs.push(unocss({
2326
2293
  ...resolveSubOptions(options, "unocss"),
2327
2294
  overrides: getOverrides(options, "unocss")
@@ -2367,6 +2334,7 @@ function config(options = {}, ...userConfigs) {
2367
2334
  if (Object.keys(fusedConfig).length) configs.push([fusedConfig]);
2368
2335
  let composer = new FlatConfigComposer();
2369
2336
  composer = composer.append(...configs, ...userConfigs);
2337
+ if (options.markdown ?? true) composer = composer.setDefaultIgnores((prev) => [...prev, GLOB_MARKDOWN]);
2370
2338
  if (autoRenamePlugins) composer = composer.renamePlugins(defaultPluginRenaming);
2371
2339
  if (isInEditor) composer = composer.disableRulesFix([
2372
2340
  "unused-imports/no-unused-imports",
@@ -2375,9 +2343,17 @@ function config(options = {}, ...userConfigs) {
2375
2343
  ], { builtinRules: () => import(["eslint", "use-at-your-own-risk"].join("/")).then((r) => r.builtinRules) });
2376
2344
  return composer;
2377
2345
  }
2346
+ function resolveSubOptions(options, key) {
2347
+ return typeof options[key] === "boolean" ? {} : options[key] || {};
2348
+ }
2349
+ function getOverrides(options, key) {
2350
+ const sub = resolveSubOptions(options, key);
2351
+ return { ..."overrides" in sub ? sub.overrides : {} };
2352
+ }
2378
2353
  //#endregion
2379
2354
  //#region src/config-presets.ts
2380
2355
  const CONFIG_PRESET_FULL_ON = {
2356
+ baseline: true,
2381
2357
  formatters: true,
2382
2358
  gitignore: true,
2383
2359
  imports: true,
@@ -2388,11 +2364,11 @@ const CONFIG_PRESET_FULL_ON = {
2388
2364
  nextjs: true,
2389
2365
  node: true,
2390
2366
  pnpm: true,
2391
- react: { reactCompiler: true },
2392
- reactNative: { expo: true },
2367
+ react: true,
2393
2368
  regexp: true,
2369
+ sonarjs: true,
2394
2370
  stylistic: { experimental: true },
2395
- tailwindcss: true,
2371
+ tailwindcss: { entryPoint: "fixtures/stub.css" },
2396
2372
  test: true,
2397
2373
  toml: true,
2398
2374
  typescript: {
@@ -2405,6 +2381,7 @@ const CONFIG_PRESET_FULL_ON = {
2405
2381
  yaml: true
2406
2382
  };
2407
2383
  const CONFIG_PRESET_FULL_OFF = {
2384
+ baseline: false,
2408
2385
  formatters: false,
2409
2386
  gitignore: false,
2410
2387
  imports: false,
@@ -2416,8 +2393,8 @@ const CONFIG_PRESET_FULL_OFF = {
2416
2393
  node: false,
2417
2394
  pnpm: false,
2418
2395
  react: false,
2419
- reactNative: false,
2420
2396
  regexp: false,
2397
+ sonarjs: false,
2421
2398
  stylistic: false,
2422
2399
  tailwindcss: false,
2423
2400
  test: false,
@@ -2432,4 +2409,4 @@ const CONFIG_PRESET_FULL_OFF = {
2432
2409
  //#region src/index.ts
2433
2410
  var src_default = config;
2434
2411
  //#endregion
2435
- export { CONFIG_PRESET_FULL_OFF, CONFIG_PRESET_FULL_ON, GLOB_ALL_SRC, GLOB_CSS, GLOB_EXCLUDE, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_MARKDOWN, GLOB_MARKDOWN_CODE, GLOB_MARKDOWN_IN_MARKDOWN, GLOB_POSTCSS, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_SVG, GLOB_TESTS, GLOB_TOML, GLOB_TS, GLOB_TSX, GLOB_VUE, GLOB_XML, GLOB_YAML, StylisticConfigDefaults, combine, command, comments, config, src_default as default, defaultPluginRenaming, disables, ensurePackages, formatters, getOverrides, ignores, imports, interopDefault, isInEditorEnv, isInGitHooksOrLintStaged, isPackageInScope, javascript, jsdoc, jsonc, jsx, markdown, nextjs, node, parserPlain, perfectionist, pnpm, react, reactNative, regexp, renameRules, resolveSubOptions, sortPackageJson, sortTsconfig, stylistic, tailwindcss, test, toml, typescript, unicorn, unocss, vue, yaml };
2412
+ export { CONFIG_PRESET_FULL_OFF, CONFIG_PRESET_FULL_ON, GLOB_ALL_SRC, GLOB_CSS, GLOB_EXCLUDE, GLOB_GRAPHQL, GLOB_HTML, GLOB_JS, GLOB_JSON, GLOB_JSON5, GLOB_JSONC, GLOB_JSX, GLOB_LESS, GLOB_MARKDOWN, GLOB_MARKDOWN_CODE, GLOB_MARKDOWN_IN_MARKDOWN, GLOB_POSTCSS, GLOB_SCSS, GLOB_SRC, GLOB_SRC_EXT, GLOB_STYLE, GLOB_SVG, GLOB_TESTS, GLOB_TOML, GLOB_TS, GLOB_TSX, GLOB_VUE, GLOB_XML, GLOB_YAML, StylisticConfigDefaults, baseline, command, comments, config, deMorgan, src_default as default, defaultPluginRenaming, disables, e18e, ensurePackages, formatters, getOverrides, ignores, imports, interopDefault, isInEditorEnv, isInGitHooksOrLintStaged, isPackageInScope, javascript, jsdoc, jsonc, jsx, markdown, nextjs, node, parserPlain, perfectionist, pnpm, preferEarlyReturn, react, regexp, renameRules, resolveSubOptions, sonarjs, sortPackageJson, sortTsconfig, stylistic, tailwindcss, test, toml, typescript, unicorn, unocss, vue, yaml };