@antfu/eslint-config 9.5.0 → 9.5.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/README.md CHANGED
@@ -336,36 +336,38 @@ And that's it! Or you can configure each integration individually, for example:
336
336
  import antfu from '@antfu/eslint-config'
337
337
 
338
338
  export default antfu({
339
- // Type of the project. 'lib' for libraries, the default is 'app'
339
+ /** Type of the project. 'lib' for libraries, the default is 'app' */
340
340
  type: 'lib',
341
341
 
342
- // `.eslintignore` is no longer supported in Flat config, use `ignores` instead
343
- // The `ignores` option in the option (first argument) is specifically treated to always be global ignores
344
- // And will **extend** the config's default ignores, not override them
345
- // You can also pass a function to modify the default ignores
342
+ /**
343
+ * `.eslintignore` is no longer supported in Flat config, use `ignores` instead
344
+ * The `ignores` option in the option (first argument) is specifically treated to always be global ignores
345
+ * And will **extend** the config's default ignores, not override them
346
+ * You can also pass a function to modify the default ignores
347
+ */
346
348
  ignores: [
347
349
  '**/fixtures',
348
350
  // ...globs
349
351
  ],
350
352
 
351
- // Parse the `.gitignore` file to get the ignores, on by default
353
+ /** Parse the `.gitignore` file to get the ignores, on by default */
352
354
  gitignore: true,
353
355
 
354
356
  // Enable stylistic formatting rules
355
357
  // stylistic: true,
356
358
 
357
- // Or customize the stylistic rules
359
+ /** Or customize the stylistic rules */
358
360
  stylistic: {
359
361
  indent: 2, // 4, or 'tab'
360
362
  quotes: 'single', // or 'double'
361
363
  braceStyle: 'stroustrup', // '1tbs', or 'allman'
362
364
  },
363
365
 
364
- // TypeScript and Vue are autodetected, you can also explicitly enable them:
366
+ /** TypeScript and Vue are autodetected, you can also explicitly enable them: */
365
367
  typescript: true,
366
368
  vue: true,
367
369
 
368
- // Disable jsonc and yaml support
370
+ /** Disable jsonc and yaml support */
369
371
  jsonc: false,
370
372
  yaml: false,
371
373
  })
@@ -514,14 +516,14 @@ export default antfu(
514
516
  typescript: true
515
517
  },
516
518
  {
517
- // Remember to specify the file glob here, otherwise it might cause the vue plugin to handle non-vue files
519
+ /** Remember to specify the file glob here, otherwise it might cause the vue plugin to handle non-vue files */
518
520
  files: ['**/*.vue'],
519
521
  rules: {
520
522
  'vue/operator-linebreak': ['error', 'before'],
521
523
  },
522
524
  },
523
525
  {
524
- // Without `files`, they are general rules for all files (Markdown excluded see note below)
526
+ /** Without `files`, they are general rules for all files (Markdown excluded, see note below) */
525
527
  rules: {
526
528
  'style/semi': ['error', 'never'],
527
529
  },
@@ -548,7 +550,7 @@ export default antfu({
548
550
  overrides: {
549
551
  'ts/consistent-type-definitions': ['error', 'interface'],
550
552
  },
551
- // type aware rules overrides should write here
553
+ /** type aware rules overrides should write here */
552
554
  overridesTypeAware: {
553
555
  'ts/no-unsafe-assignment': ['warn'],
554
556
  }
@@ -841,8 +843,10 @@ import antfu from '@antfu/eslint-config'
841
843
  export default antfu({
842
844
  antislop: {
843
845
  sonarjs: false,
844
- // an object enables `eslint-plugin-slop` and is forwarded to it
845
- // via `settings.slop`, for example to only inspect recently changed code
846
+ /**
847
+ * an object enables `eslint-plugin-slop` and is forwarded to it
848
+ * via `settings.slop`, for example to only inspect recently changed code
849
+ */
846
850
  slop: {
847
851
  inspection: { mode: 'recent-changes', tracebackCommits: 5 },
848
852
  },
package/dist/cli.mjs CHANGED
@@ -8,7 +8,7 @@ import { cac } from "cac";
8
8
  import parse from "parse-gitignore";
9
9
  import { execSync } from "node:child_process";
10
10
  //#region package.json
11
- var version = "9.5.0";
11
+ var version = "9.5.1";
12
12
  //#endregion
13
13
  //#region src/cli/constants.ts
14
14
  const vscodeSettingsString = `
@@ -188,21 +188,22 @@ async function updatePackageJson(result) {
188
188
  const pkgContent = await fsPromises.readFile(pathPackageJSON, "utf-8");
189
189
  const pkg = JSON.parse(pkgContent);
190
190
  pkg.devDependencies ??= {};
191
- pkg.devDependencies["@antfu/eslint-config"] = `^${version}`;
192
- pkg.devDependencies.eslint ??= versionsMap.eslint;
191
+ const devDependencies = pkg.devDependencies;
192
+ devDependencies["@antfu/eslint-config"] = `^${version}`;
193
+ devDependencies.eslint ??= versionsMap.eslint;
193
194
  const addedPackages = [];
194
195
  if (result.extra.length) result.extra.forEach((item) => {
195
196
  switch (item) {
196
197
  case "formatter":
197
198
  [...dependenciesMap.formatter, ...result.frameworks.includes("astro") ? dependenciesMap.formatterAstro : []].forEach((f) => {
198
199
  if (!f) return;
199
- pkg.devDependencies[f] = versionsMap[f];
200
+ devDependencies[f] = versionsMap[f];
200
201
  addedPackages.push(f);
201
202
  });
202
203
  break;
203
204
  case "unocss":
204
205
  dependenciesMap.unocss.forEach((f) => {
205
- pkg.devDependencies[f] = versionsMap[f];
206
+ devDependencies[f] = versionsMap[f];
206
207
  addedPackages.push(f);
207
208
  });
208
209
  break;
@@ -211,7 +212,7 @@ async function updatePackageJson(result) {
211
212
  for (const framework of result.frameworks) {
212
213
  const deps = dependenciesMap[framework];
213
214
  if (deps) deps.forEach((f) => {
214
- pkg.devDependencies[f] = versionsMap[f];
215
+ devDependencies[f] = versionsMap[f];
215
216
  addedPackages.push(f);
216
217
  });
217
218
  }
@@ -259,7 +260,7 @@ async function run(options = {}) {
259
260
  if (!argSkipPrompt) {
260
261
  result = await p.group({
261
262
  uncommittedConfirmed: () => {
262
- if (argSkipPrompt || isGitClean()) return Promise.resolve(true);
263
+ if (isGitClean()) return Promise.resolve(true);
263
264
  return p.confirm({
264
265
  initialValue: false,
265
266
  message: "There are uncommitted changes in the current repository, are you sure to continue?"
package/dist/index.d.mts CHANGED
@@ -23418,7 +23418,7 @@ type Yoda = [] | [("always" | "never")] | [("always" | "never"), {
23418
23418
  onlyEquality?: boolean;
23419
23419
  }];
23420
23420
  // Names of all the configs
23421
- type ConfigNames = 'antfu/gitignore' | 'antfu/ignores' | 'antfu/javascript/setup' | 'antfu/javascript/rules' | 'antfu/eslint-comments/rules' | 'antfu/command/rules' | 'antfu/perfectionist/setup' | 'antfu/node/setup' | 'antfu/node/rules' | 'antfu/jsdoc/setup' | 'antfu/jsdoc/rules' | 'antfu/imports/rules' | 'antfu/e18e/rules' | 'antfu/unicorn/setup' | 'antfu/unicorn/rules' | 'antfu/jsx/setup' | 'antfu/typescript/setup' | 'antfu/typescript/parser' | 'antfu/typescript/type-aware-parser' | 'antfu/typescript/rules' | 'antfu/typescript/rules-type-aware' | 'antfu/typescript/erasable-syntax-only' | 'antfu/antislop/rules' | 'antfu/stylistic/rules' | 'antfu/regexp/rules' | 'antfu/test/setup' | 'antfu/test/rules' | 'antfu/vue/setup' | 'antfu/vue/rules' | 'antfu/react/setup' | 'antfu/react/rules' | 'antfu/react/typescript' | 'antfu/react/type-aware-rules' | 'antfu/nextjs/setup' | 'antfu/nextjs/rules' | 'antfu/solid/setup' | 'antfu/solid/rules' | 'antfu/svelte/setup' | 'antfu/svelte/rules' | 'antfu/unocss' | 'antfu/astro/setup' | 'antfu/astro/rules' | 'antfu/angular/setup' | 'antfu/angular/rules/ts' | 'antfu/angular/rules/template' | 'antfu/jsonc/setup' | 'antfu/jsonc/rules' | 'antfu/sort/package-json' | 'antfu/sort/tsconfig-json' | 'antfu/pnpm/package-json' | 'antfu/pnpm/pnpm-workspace-yaml' | 'antfu/pnpm/pnpm-workspace-yaml-stylistic' | 'antfu/pnpm/pnpm-workspace-yaml-sort' | 'antfu/yaml/setup' | 'antfu/yaml/rules' | 'antfu/toml/setup' | 'antfu/toml/rules' | 'antfu/markdown/setup' | 'antfu/markdown/processor' | 'antfu/markdown/parser' | 'antfu/markdown/rules' | 'antfu/markdown/disables/code' | 'antfu/formatter/setup' | 'antfu/formatter/css' | 'antfu/formatter/scss' | 'antfu/formatter/less' | 'antfu/formatter/html' | 'antfu/formatter/xml' | 'antfu/formatter/svg' | 'antfu/formatter/markdown' | 'antfu/formatter/astro' | 'antfu/formatter/astro/disables' | 'antfu/formatter/graphql' | 'antfu/disables/scripts' | 'antfu/disables/cli' | 'antfu/disables/bin' | 'antfu/disables/dts' | 'antfu/disables/cjs' | 'antfu/disables/config-files';
23421
+ type ConfigNames = 'antfu/gitignore' | 'antfu/ignores' | 'antfu/javascript/setup' | 'antfu/javascript/rules' | 'antfu/eslint-comments/rules' | 'antfu/command/rules' | 'antfu/perfectionist/setup' | 'antfu/node/setup' | 'antfu/node/rules' | 'antfu/jsdoc/setup' | 'antfu/jsdoc/rules' | 'antfu/imports/rules' | 'antfu/e18e/rules' | 'antfu/unicorn/setup' | 'antfu/unicorn/rules' | 'antfu/jsx/setup' | 'antfu/typescript/setup' | 'antfu/typescript/parser' | 'antfu/typescript/type-aware-parser' | 'antfu/typescript/rules' | 'antfu/typescript/rules-type-aware' | 'antfu/typescript/erasable-syntax-only' | 'antfu/antislop/setup' | 'antfu/antislop/rules/universal' | 'antfu/antislop/rules/javascript' | 'antfu/stylistic/rules' | 'antfu/regexp/rules' | 'antfu/test/setup' | 'antfu/test/rules' | 'antfu/vue/setup' | 'antfu/vue/rules' | 'antfu/react/setup' | 'antfu/react/rules' | 'antfu/react/typescript' | 'antfu/react/type-aware-rules' | 'antfu/nextjs/setup' | 'antfu/nextjs/rules' | 'antfu/solid/setup' | 'antfu/solid/rules' | 'antfu/svelte/setup' | 'antfu/svelte/rules' | 'antfu/unocss' | 'antfu/astro/setup' | 'antfu/astro/rules' | 'antfu/angular/setup' | 'antfu/angular/rules/ts' | 'antfu/angular/rules/template' | 'antfu/jsonc/setup' | 'antfu/jsonc/rules' | 'antfu/sort/package-json' | 'antfu/sort/tsconfig-json' | 'antfu/pnpm/package-json' | 'antfu/pnpm/pnpm-workspace-yaml' | 'antfu/pnpm/pnpm-workspace-yaml-stylistic' | 'antfu/pnpm/pnpm-workspace-yaml-sort' | 'antfu/yaml/setup' | 'antfu/yaml/rules' | 'antfu/toml/setup' | 'antfu/toml/rules' | 'antfu/markdown/setup' | 'antfu/markdown/processor' | 'antfu/markdown/parser' | 'antfu/markdown/rules' | 'antfu/markdown/disables/code' | 'antfu/formatter/setup' | 'antfu/formatter/css' | 'antfu/formatter/scss' | 'antfu/formatter/less' | 'antfu/formatter/html' | 'antfu/formatter/xml' | 'antfu/formatter/svg' | 'antfu/formatter/markdown' | 'antfu/formatter/astro' | 'antfu/formatter/astro/disables' | 'antfu/formatter/graphql' | 'antfu/disables/scripts' | 'antfu/disables/cli' | 'antfu/disables/bin' | 'antfu/disables/dts' | 'antfu/disables/cjs' | 'antfu/disables/config-files';
23422
23422
  //#endregion
23423
23423
  //#region src/vender/prettier-types.d.ts
23424
23424
  /**
@@ -23492,7 +23492,7 @@ interface VendoredPrettierOptionsRequired {
23492
23492
  /**
23493
23493
  * Provide ability to support new languages to prettier.
23494
23494
  */
23495
- plugins: Array<string | any>;
23495
+ plugins: Array<string | Record<string, unknown>>;
23496
23496
  /**
23497
23497
  * How to handle whitespaces in HTML.
23498
23498
  * @default "css"
@@ -23727,6 +23727,14 @@ interface OptionsAntislop extends OptionsOverrides {
23727
23727
  * @default true
23728
23728
  */
23729
23729
  sonarjs?: boolean;
23730
+ /**
23731
+ * Maximum allowed cognitive complexity for `sonarjs/cognitive-complexity`.
23732
+ *
23733
+ * Pass `false` to disable the rule entirely.
23734
+ *
23735
+ * @default 15
23736
+ */
23737
+ cognitiveComplexity?: number | false;
23730
23738
  }
23731
23739
  interface OptionsUnicorn extends OptionsOverrides {
23732
23740
  /**
@@ -24156,6 +24164,7 @@ declare function resolveSubOptions<K extends keyof OptionsConfig>(options: Optio
24156
24164
  declare function getOverrides<K extends keyof OptionsConfig>(options: OptionsConfig, key: K): Partial<Linter.RulesRecord & RuleOptions>;
24157
24165
  //#endregion
24158
24166
  //#region src/config-presets.d.ts
24167
+ /** @keep-sorted */
24159
24168
  declare const CONFIG_PRESET_FULL_ON: OptionsConfig;
24160
24169
  declare const CONFIG_PRESET_FULL_OFF: OptionsConfig;
24161
24170
  //#endregion
@@ -24178,7 +24187,7 @@ declare function comments(): Promise<TypedFlatConfigItem[]>;
24178
24187
  declare function disables(): Promise<TypedFlatConfigItem[]>;
24179
24188
  //#endregion
24180
24189
  //#region src/configs/formatters.d.ts
24181
- declare function formatters(options?: OptionsFormatters | true, stylistic?: StylisticConfig): Promise<TypedFlatConfigItem[]>;
24190
+ declare function formatters(rawOptions?: OptionsFormatters | true, stylistic?: StylisticConfig): Promise<TypedFlatConfigItem[]>;
24182
24191
  //#endregion
24183
24192
  //#region src/configs/ignores.d.ts
24184
24193
  declare function ignores(userIgnores?: string[] | ((originals: string[]) => string[]), ignoreTypeScript?: boolean): Promise<TypedFlatConfigItem[]>;
package/dist/index.mjs CHANGED
@@ -307,51 +307,71 @@ async function angular(options = {}) {
307
307
  //#endregion
308
308
  //#region src/configs/antislop.ts
309
309
  async function antislop(options = {}) {
310
- const { overrides = {}, slop = true, sonarjs = true, typescript = false } = options;
310
+ const { cognitiveComplexity = 15, overrides = {}, slop = true, sonarjs = true } = options;
311
311
  await ensurePackages([...slop ? ["eslint-plugin-slop"] : [], ...sonarjs ? ["eslint-plugin-sonarjs"] : []]);
312
312
  const [pluginSlop, pluginSonarjs] = await Promise.all([slop ? interopDefault(import("eslint-plugin-slop")) : void 0, sonarjs ? interopDefault(import("eslint-plugin-sonarjs")) : void 0]);
313
- return [{
314
- name: "antfu/antislop/rules",
315
- plugins: {
316
- ...slop ? { slop: pluginSlop } : {},
317
- ...sonarjs ? { sonarjs: pluginSonarjs } : {}
313
+ return [
314
+ {
315
+ name: "antfu/antislop/setup",
316
+ plugins: {
317
+ ...slop ? { slop: pluginSlop } : {},
318
+ ...sonarjs ? { sonarjs: pluginSonarjs } : {}
319
+ },
320
+ ...typeof slop === "object" ? { settings: { slop } } : {}
318
321
  },
319
- ...typeof slop === "object" ? { settings: { slop } } : {},
320
- rules: {
321
- ...slop ? {
322
- "slop/max-comment-length": "error",
323
- "slop/no-chained-type-assertions": "error",
324
- "slop/no-em-dash": "error",
325
- "slop/no-jargon": "error",
326
- "slop/no-trivial-functions": "error",
327
- "slop/no-trivial-type-aliases": "error",
328
- "slop/prefer-jsdoc": "error"
329
- } : {},
330
- ...sonarjs ? {
331
- "sonarjs/cognitive-complexity": "error",
332
- "sonarjs/no-all-duplicated-branches": "error",
333
- "sonarjs/no-collapsible-if": "error",
334
- "sonarjs/no-commented-code": "error",
335
- "sonarjs/no-dead-store": "error",
336
- "sonarjs/no-duplicated-branches": "error",
337
- "sonarjs/no-element-overwrite": "error",
338
- "sonarjs/no-empty-collection": "error",
339
- "sonarjs/no-gratuitous-expressions": "error",
340
- "sonarjs/no-identical-conditions": "error",
341
- "sonarjs/no-identical-expressions": "error",
342
- "sonarjs/no-identical-functions": "error",
343
- "sonarjs/no-invariant-returns": "error",
344
- "sonarjs/no-inverted-boolean-check": "error",
345
- "sonarjs/no-redundant-boolean": "error",
346
- "sonarjs/no-redundant-jump": "error",
347
- "sonarjs/no-unused-collection": "error",
348
- "sonarjs/no-use-of-empty-return-value": "error",
349
- "sonarjs/prefer-single-boolean-return": "error"
350
- } : {},
351
- ...typescript ? { "ts/no-explicit-any": "error" } : {},
352
- ...overrides
322
+ ...slop ? [{
323
+ files: [
324
+ ...GLOB_ALL_SRC,
325
+ GLOB_JSONC,
326
+ GLOB_TOML,
327
+ GLOB_GRAPHQL
328
+ ],
329
+ /**
330
+ * Markdown code fences are already scanned as part of the raw
331
+ * Markdown text, so exclude the virtual embedded-code files to
332
+ * avoid reporting the same em dash twice
333
+ */
334
+ ignores: [GLOB_MARKDOWN_CODE],
335
+ name: "antfu/antislop/rules/universal",
336
+ rules: { "slop/no-em-dash": "error" }
337
+ }] : [],
338
+ {
339
+ files: [GLOB_SRC],
340
+ name: "antfu/antislop/rules/javascript",
341
+ rules: {
342
+ ...slop ? {
343
+ "slop/max-comment-length": "error",
344
+ "slop/no-chained-type-assertions": "error",
345
+ "slop/no-jargon": "error",
346
+ "slop/no-trivial-functions": "error",
347
+ "slop/no-trivial-type-aliases": "error",
348
+ "slop/prefer-jsdoc": "error"
349
+ } : {},
350
+ ...sonarjs ? {
351
+ ...cognitiveComplexity === false ? {} : { "sonarjs/cognitive-complexity": ["error", cognitiveComplexity] },
352
+ "sonarjs/no-all-duplicated-branches": "error",
353
+ "sonarjs/no-collapsible-if": "error",
354
+ "sonarjs/no-commented-code": "error",
355
+ "sonarjs/no-dead-store": "error",
356
+ "sonarjs/no-duplicated-branches": "error",
357
+ "sonarjs/no-element-overwrite": "error",
358
+ "sonarjs/no-empty-collection": "error",
359
+ "sonarjs/no-gratuitous-expressions": "error",
360
+ "sonarjs/no-identical-conditions": "error",
361
+ "sonarjs/no-identical-expressions": "error",
362
+ "sonarjs/no-identical-functions": "error",
363
+ "sonarjs/no-invariant-returns": "error",
364
+ "sonarjs/no-inverted-boolean-check": "error",
365
+ "sonarjs/no-redundant-boolean": "error",
366
+ "sonarjs/no-redundant-jump": "error",
367
+ "sonarjs/no-unused-collection": "error",
368
+ "sonarjs/no-use-of-empty-return-value": "error",
369
+ "sonarjs/prefer-single-boolean-return": "error"
370
+ } : {},
371
+ ...overrides
372
+ }
353
373
  }
354
- }];
374
+ ];
355
375
  }
356
376
  //#endregion
357
377
  //#region src/configs/astro.ts
@@ -379,7 +399,12 @@ async function astro(options = {}) {
379
399
  name: "antfu/astro/rules",
380
400
  processor: "astro/client-side-ts",
381
401
  rules: {
402
+ /**
403
+ * Astro uses top level await for e.g. data fetching
404
+ * https://docs.astro.build/en/guides/data-fetching/#fetch-in-astro
405
+ */
382
406
  "antfu/no-top-level-await": "off",
407
+ /** use recommended rules */
383
408
  "astro/missing-client-only-directive-value": "error",
384
409
  "astro/no-conflict-set-directives": "error",
385
410
  "astro/no-deprecated-astro-canonicalurl": "error",
@@ -537,26 +562,136 @@ function mergePrettierOptions(options, overrides) {
537
562
  plugins: [...overrides.plugins || [], ...options.plugins || []]
538
563
  };
539
564
  }
540
- async function formatters(options = {}, stylistic = {}) {
541
- if (options === true) {
542
- const isPrettierPluginXmlInScope = isPackageInScope("@prettier/plugin-xml");
543
- options = {
544
- astro: isPackageInScope("prettier-plugin-astro"),
545
- css: true,
546
- graphql: true,
547
- html: true,
548
- markdown: true,
549
- slidev: isPackageExists("@slidev/cli"),
550
- svg: isPrettierPluginXmlInScope,
551
- xml: isPrettierPluginXmlInScope
552
- };
553
- }
554
- await ensurePackages([
565
+ function buildCssConfigs(prettierOptions) {
566
+ return [
567
+ [
568
+ [GLOB_CSS, GLOB_POSTCSS],
569
+ "css",
570
+ "antfu/formatter/css"
571
+ ],
572
+ [
573
+ [GLOB_SCSS],
574
+ "scss",
575
+ "antfu/formatter/scss"
576
+ ],
577
+ [
578
+ [GLOB_LESS],
579
+ "less",
580
+ "antfu/formatter/less"
581
+ ]
582
+ ].map(([files, parser, name]) => ({
583
+ files: [...files],
584
+ languageOptions: { parser: parserPlain },
585
+ name,
586
+ rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser })] }
587
+ }));
588
+ }
589
+ function buildXmlLikeConfig(prettierOptions, prettierXmlOptions, files, name) {
590
+ return {
591
+ files,
592
+ languageOptions: { parser: parserPlain },
593
+ name,
594
+ rules: { "format/prettier": ["error", mergePrettierOptions({
595
+ ...prettierXmlOptions,
596
+ ...prettierOptions
597
+ }, {
598
+ parser: "xml",
599
+ plugins: ["@prettier/plugin-xml"]
600
+ })] }
601
+ };
602
+ }
603
+ function buildMarkdownConfigs(options, prettierOptions, dprintOptions) {
604
+ const formater = options.markdown === true ? "prettier" : options.markdown;
605
+ const GLOB_SLIDEV = !options.slidev ? [] : options.slidev === true ? ["**/slides.md"] : options.slidev.files;
606
+ const configs = [{
607
+ files: [GLOB_MARKDOWN],
608
+ ignores: GLOB_SLIDEV,
609
+ languageOptions: { parser: parserPlain },
610
+ name: "antfu/formatter/markdown",
611
+ rules: { [`format/${formater}`]: ["error", formater === "prettier" ? mergePrettierOptions(prettierOptions, {
612
+ embeddedLanguageFormatting: "off",
613
+ parser: "markdown"
614
+ }) : {
615
+ ...dprintOptions,
616
+ language: "markdown"
617
+ }] }
618
+ }];
619
+ if (options.slidev) configs.push({
620
+ files: GLOB_SLIDEV,
621
+ languageOptions: { parser: parserPlain },
622
+ name: "antfu/formatter/slidev",
623
+ rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, {
624
+ embeddedLanguageFormatting: "off",
625
+ parser: "slidev",
626
+ plugins: ["prettier-plugin-slidev"]
627
+ })] }
628
+ });
629
+ return configs;
630
+ }
631
+ function buildAstroConfigs(prettierOptions) {
632
+ return [{
633
+ files: [GLOB_ASTRO],
634
+ languageOptions: { parser: parserPlain },
635
+ name: "antfu/formatter/astro",
636
+ rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, {
637
+ parser: "astro",
638
+ plugins: ["prettier-plugin-astro"]
639
+ })] }
640
+ }, {
641
+ files: [GLOB_ASTRO, GLOB_ASTRO_TS],
642
+ name: "antfu/formatter/astro/disables",
643
+ rules: {
644
+ "style/arrow-parens": "off",
645
+ "style/block-spacing": "off",
646
+ "style/comma-dangle": "off",
647
+ "style/indent": "off",
648
+ "style/no-multi-spaces": "off",
649
+ "style/quotes": "off",
650
+ "style/semi": "off"
651
+ }
652
+ }];
653
+ }
654
+ function resolveFormattersOptions(options) {
655
+ if (options !== true) return options;
656
+ const isPrettierPluginXmlInScope = isPackageInScope("@prettier/plugin-xml");
657
+ return {
658
+ astro: isPackageInScope("prettier-plugin-astro"),
659
+ css: true,
660
+ graphql: true,
661
+ html: true,
662
+ markdown: true,
663
+ slidev: isPackageExists("@slidev/cli"),
664
+ svg: isPrettierPluginXmlInScope,
665
+ xml: isPrettierPluginXmlInScope
666
+ };
667
+ }
668
+ function buildHtmlConfig(prettierOptions) {
669
+ return {
670
+ files: [GLOB_HTML],
671
+ languageOptions: { parser: parserPlain },
672
+ name: "antfu/formatter/html",
673
+ rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "html" })] }
674
+ };
675
+ }
676
+ function buildGraphqlConfig(prettierOptions) {
677
+ return {
678
+ files: [GLOB_GRAPHQL],
679
+ languageOptions: { parser: parserPlain },
680
+ name: "antfu/formatter/graphql",
681
+ rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "graphql" })] }
682
+ };
683
+ }
684
+ function getFormattersPackagesToEnsure(options) {
685
+ return [
555
686
  "eslint-plugin-format",
556
687
  options.markdown && options.slidev ? "prettier-plugin-slidev" : void 0,
557
688
  options.astro ? "prettier-plugin-astro" : void 0,
558
689
  options.xml || options.svg ? "@prettier/plugin-xml" : void 0
559
- ]);
690
+ ];
691
+ }
692
+ async function formatters(rawOptions = {}, stylistic = {}) {
693
+ const options = resolveFormattersOptions(rawOptions);
694
+ await ensurePackages(getFormattersPackagesToEnsure(options));
560
695
  if (options.slidev && options.markdown !== true && options.markdown !== "prettier") throw new Error("`slidev` option only works when `markdown` is enabled with `prettier`");
561
696
  const { indent, quotes, semi } = {
562
697
  ...StylisticConfigDefaults,
@@ -587,109 +722,13 @@ async function formatters(options = {}, stylistic = {}) {
587
722
  name: "antfu/formatter/setup",
588
723
  plugins: { format: await interopDefault(import("eslint-plugin-format")) }
589
724
  }];
590
- if (options.css) configs.push({
591
- files: [GLOB_CSS, GLOB_POSTCSS],
592
- languageOptions: { parser: parserPlain },
593
- name: "antfu/formatter/css",
594
- rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "css" })] }
595
- }, {
596
- files: [GLOB_SCSS],
597
- languageOptions: { parser: parserPlain },
598
- name: "antfu/formatter/scss",
599
- rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "scss" })] }
600
- }, {
601
- files: [GLOB_LESS],
602
- languageOptions: { parser: parserPlain },
603
- name: "antfu/formatter/less",
604
- rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "less" })] }
605
- });
606
- if (options.html) configs.push({
607
- files: [GLOB_HTML],
608
- languageOptions: { parser: parserPlain },
609
- name: "antfu/formatter/html",
610
- rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "html" })] }
611
- });
612
- if (options.xml) configs.push({
613
- files: [GLOB_XML],
614
- languageOptions: { parser: parserPlain },
615
- name: "antfu/formatter/xml",
616
- rules: { "format/prettier": ["error", mergePrettierOptions({
617
- ...prettierXmlOptions,
618
- ...prettierOptions
619
- }, {
620
- parser: "xml",
621
- plugins: ["@prettier/plugin-xml"]
622
- })] }
623
- });
624
- if (options.svg) configs.push({
625
- files: [GLOB_SVG],
626
- languageOptions: { parser: parserPlain },
627
- name: "antfu/formatter/svg",
628
- rules: { "format/prettier": ["error", mergePrettierOptions({
629
- ...prettierXmlOptions,
630
- ...prettierOptions
631
- }, {
632
- parser: "xml",
633
- plugins: ["@prettier/plugin-xml"]
634
- })] }
635
- });
636
- if (options.markdown) {
637
- const formater = options.markdown === true ? "prettier" : options.markdown;
638
- const GLOB_SLIDEV = !options.slidev ? [] : options.slidev === true ? ["**/slides.md"] : options.slidev.files;
639
- configs.push({
640
- files: [GLOB_MARKDOWN],
641
- ignores: GLOB_SLIDEV,
642
- languageOptions: { parser: parserPlain },
643
- name: "antfu/formatter/markdown",
644
- rules: { [`format/${formater}`]: ["error", formater === "prettier" ? mergePrettierOptions(prettierOptions, {
645
- embeddedLanguageFormatting: "off",
646
- parser: "markdown"
647
- }) : {
648
- ...dprintOptions,
649
- language: "markdown"
650
- }] }
651
- });
652
- if (options.slidev) configs.push({
653
- files: GLOB_SLIDEV,
654
- languageOptions: { parser: parserPlain },
655
- name: "antfu/formatter/slidev",
656
- rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, {
657
- embeddedLanguageFormatting: "off",
658
- parser: "slidev",
659
- plugins: ["prettier-plugin-slidev"]
660
- })] }
661
- });
662
- }
663
- if (options.astro) {
664
- configs.push({
665
- files: [GLOB_ASTRO],
666
- languageOptions: { parser: parserPlain },
667
- name: "antfu/formatter/astro",
668
- rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, {
669
- parser: "astro",
670
- plugins: ["prettier-plugin-astro"]
671
- })] }
672
- });
673
- configs.push({
674
- files: [GLOB_ASTRO, GLOB_ASTRO_TS],
675
- name: "antfu/formatter/astro/disables",
676
- rules: {
677
- "style/arrow-parens": "off",
678
- "style/block-spacing": "off",
679
- "style/comma-dangle": "off",
680
- "style/indent": "off",
681
- "style/no-multi-spaces": "off",
682
- "style/quotes": "off",
683
- "style/semi": "off"
684
- }
685
- });
686
- }
687
- if (options.graphql) configs.push({
688
- files: [GLOB_GRAPHQL],
689
- languageOptions: { parser: parserPlain },
690
- name: "antfu/formatter/graphql",
691
- rules: { "format/prettier": ["error", mergePrettierOptions(prettierOptions, { parser: "graphql" })] }
692
- });
725
+ if (options.css) configs.push(...buildCssConfigs(prettierOptions));
726
+ if (options.html) configs.push(buildHtmlConfig(prettierOptions));
727
+ if (options.xml) configs.push(buildXmlLikeConfig(prettierOptions, prettierXmlOptions, [GLOB_XML], "antfu/formatter/xml"));
728
+ if (options.svg) configs.push(buildXmlLikeConfig(prettierOptions, prettierXmlOptions, [GLOB_SVG], "antfu/formatter/svg"));
729
+ if (options.markdown) configs.push(...buildMarkdownConfigs(options, prettierOptions, dprintOptions));
730
+ if (options.astro) configs.push(...buildAstroConfigs(prettierOptions));
731
+ if (options.graphql) configs.push(buildGraphqlConfig(prettierOptions));
693
732
  return configs;
694
733
  }
695
734
  //#endregion
@@ -1102,6 +1141,11 @@ async function markdown(options = {}) {
1102
1141
  files,
1103
1142
  ignores: [GLOB_MARKDOWN_IN_MARKDOWN],
1104
1143
  name: "antfu/markdown/processor",
1144
+ /**
1145
+ * `eslint-plugin-markdown` only creates virtual files for code blocks,
1146
+ * but not the markdown file itself. We use `eslint-merge-processors` to
1147
+ * add a pass-through processor for the markdown file itself.
1148
+ */
1105
1149
  processor: mergeProcessors([markdown.processors.markdown, processorPassThrough])
1106
1150
  },
1107
1151
  {
@@ -1115,6 +1159,7 @@ async function markdown(options = {}) {
1115
1159
  rules: {
1116
1160
  ...markdown.configs.recommended.at(0)?.rules,
1117
1161
  "markdown/fenced-code-language": "off",
1162
+ /** https://github.com/eslint/markdown/issues/294 */
1118
1163
  "markdown/no-missing-label-refs": "off",
1119
1164
  ...overridesMarkdown
1120
1165
  }
@@ -1309,14 +1354,14 @@ async function pnpm(options) {
1309
1354
  "pnpm/yaml-no-unused-catalog-item": "error"
1310
1355
  }
1311
1356
  });
1312
- if (yaml && stylistic) configs.push({
1357
+ if (stylistic) configs.push({
1313
1358
  files: ["pnpm-workspace.yaml"],
1314
1359
  languageOptions: { parser: yamlParser },
1315
1360
  name: "antfu/pnpm/pnpm-workspace-yaml-stylistic",
1316
1361
  plugins: { pnpm: pluginPnpm },
1317
1362
  rules: { "pnpm/yaml-blank-lines": "error" }
1318
1363
  });
1319
- if (yaml && sort) configs.push({
1364
+ if (sort) configs.push({
1320
1365
  files: ["pnpm-workspace.yaml"],
1321
1366
  languageOptions: { parser: yamlParser },
1322
1367
  name: "antfu/pnpm/pnpm-workspace-yaml-sort",
@@ -1565,6 +1610,7 @@ async function react(options = {}) {
1565
1610
  name: "antfu/react/rules",
1566
1611
  rules: {
1567
1612
  ...pluginReact.configs.recommended.rules,
1613
+ /** preconfigured rules from eslint-plugin-react-refresh https://github.com/ArnaudBarre/eslint-plugin-react-refresh/tree/main/src */
1568
1614
  "react-refresh/only-export-components": ["error", {
1569
1615
  allowConstantExport: isAllowConstantExport,
1570
1616
  allowExportNames: [...isUsingNext ? [
@@ -1601,6 +1647,7 @@ async function react(options = {}) {
1601
1647
  files: filesTypeAware,
1602
1648
  name: "antfu/react/typescript",
1603
1649
  rules: {
1650
+ /** Disables rules that are already handled by TypeScript */
1604
1651
  "react/dom-no-string-style-prop": "off",
1605
1652
  "react/dom-no-unknown-property": "off"
1606
1653
  }
@@ -1653,17 +1700,23 @@ async function solid(options = {}) {
1653
1700
  },
1654
1701
  name: "antfu/solid/rules",
1655
1702
  rules: {
1703
+ /** reactivity */
1656
1704
  "solid/components-return-once": "warn",
1657
1705
  "solid/event-handlers": ["error", {
1706
+ /** if true, don't warn on ambiguously named event handlers like `onclick` or `onchange` */
1658
1707
  ignoreCase: false,
1708
+ /** if true, warn when spreading event handlers onto JSX. Enable for Solid < v1.6. */
1659
1709
  warnOnSpread: false
1660
1710
  }],
1711
+ /** these rules are mostly style suggestions */
1661
1712
  "solid/imports": "error",
1713
+ /** identifier usage is important */
1662
1714
  "solid/jsx-no-duplicate-props": "error",
1663
1715
  "solid/jsx-no-script-url": "error",
1664
1716
  "solid/jsx-no-undef": "error",
1665
1717
  "solid/jsx-uses-vars": "error",
1666
1718
  "solid/no-destructure": "error",
1719
+ /** security problems */
1667
1720
  "solid/no-innerhtml": ["error", { allowStatic: true }],
1668
1721
  "solid/no-react-deps": "error",
1669
1722
  "solid/no-react-specific-props": "error",
@@ -2115,6 +2168,7 @@ async function typescript(options = {}) {
2115
2168
  }
2116
2169
  return [
2117
2170
  {
2171
+ /** Install the plugins without globs, so they can be configured separately. */
2118
2172
  name: "antfu/typescript/setup",
2119
2173
  plugins: {
2120
2174
  antfu: pluginAntfu,
@@ -2257,6 +2311,10 @@ async function vue(options = {}) {
2257
2311
  ...a11y ? [interopDefault(import("eslint-plugin-vuejs-accessibility"))] : []
2258
2312
  ]);
2259
2313
  return [{
2314
+ /**
2315
+ * This allows Vue plugin to work with auto imports
2316
+ * https://github.com/vuejs/eslint-plugin-vue/pull/2422
2317
+ */
2260
2318
  languageOptions: { globals: {
2261
2319
  computed: "readonly",
2262
2320
  defineEmits: "readonly",
@@ -2327,6 +2385,7 @@ async function vue(options = {}) {
2327
2385
  ] }],
2328
2386
  "vue/component-name-in-template-casing": ["error", "PascalCase"],
2329
2387
  "vue/component-options-name-casing": ["error", "PascalCase"],
2388
+ /** this is deprecated */
2330
2389
  "vue/component-tags-order": "off",
2331
2390
  "vue/custom-event-name-casing": ["error", "camelCase"],
2332
2391
  "vue/define-macros-order": ["error", { order: [
@@ -2508,6 +2567,7 @@ async function e18e(options = {}) {
2508
2567
  ...moduleReplacements ? { ...configs.moduleReplacements.rules } : {},
2509
2568
  ...performanceImprovements ? { ...configs.performanceImprovements.rules } : {},
2510
2569
  ...type === "lib" ? {} : { "e18e/prefer-static-regex": "off" },
2570
+ /** these are a bit opinionated and dangerous (introducing behavioral changes), so we'll disable them by default for now */
2511
2571
  "e18e/prefer-array-at": "off",
2512
2572
  "e18e/prefer-array-from-map": "off",
2513
2573
  "e18e/prefer-array-to-reversed": "off",
@@ -2703,6 +2763,7 @@ function getOverrides(options, key) {
2703
2763
  }
2704
2764
  //#endregion
2705
2765
  //#region src/config-presets.ts
2766
+ /** @keep-sorted */
2706
2767
  const CONFIG_PRESET_FULL_ON = {
2707
2768
  angular: true,
2708
2769
  antislop: true,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@antfu/eslint-config",
3
3
  "type": "module",
4
- "version": "9.5.0",
4
+ "version": "9.5.1",
5
5
  "description": "Anthony's ESLint config",
6
6
  "author": "Anthony Fu <anthonyfu117@hotmail.com> (https://github.com/antfu/)",
7
7
  "license": "MIT",
@@ -159,10 +159,10 @@
159
159
  "@angular-eslint/eslint-plugin-template": "^22.2.0",
160
160
  "@angular-eslint/template-parser": "^22.2.0",
161
161
  "@angular/core": "^22.1.4",
162
- "@antfu/eslint-config": "9.5.0",
162
+ "@antfu/eslint-config": "9.5.1",
163
163
  "@antfu/ni": "^30.5.0",
164
164
  "@eslint-react/eslint-plugin": "^5.18.6",
165
- "@eslint/config-inspector": "^3.3.0",
165
+ "@eslint/config-inspector": "^3.4.0",
166
166
  "@next/eslint-plugin-next": "^16.3.3",
167
167
  "@prettier/plugin-xml": "^3.4.2",
168
168
  "@types/eslint-plugin-jsx-a11y": "^6.10.1",
@@ -177,7 +177,7 @@
177
177
  "eslint-plugin-format": "^2.0.1",
178
178
  "eslint-plugin-jsx-a11y": "^6.10.2",
179
179
  "eslint-plugin-react-refresh": "^0.5.5",
180
- "eslint-plugin-slop": "^0.1.1",
180
+ "eslint-plugin-slop": "^0.1.2",
181
181
  "eslint-plugin-solid": "^0.17.0",
182
182
  "eslint-plugin-sonarjs": "^4.2.0",
183
183
  "eslint-plugin-svelte": "^3.23.0",
@@ -226,7 +226,7 @@
226
226
  "build": "nr gen && tsdown --clean --dts",
227
227
  "stub": "tsdown",
228
228
  "dev": "npx @eslint/config-inspector --config eslint.config.ts",
229
- "build:inspector": "pnpm build && npx @eslint/config-inspector build --config eslint.config.ts --out-dir ./.eslint-config-inspector",
229
+ "build:inspector": "pnpm build && npx @eslint/config-inspector build --stats --config eslint.config.ts --out-dir ./.eslint-config-inspector",
230
230
  "watch": "tsdown --watch",
231
231
  "lint": "eslint",
232
232
  "gen": "tsx scripts/typegen.ts && tsx scripts/versiongen.ts",