Skip to content

Commit 8d25a37

Browse files
antfuclaude
andauthored
fix(markdown): scope user rule overrides away from md files (#844)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6c8395e commit 8d25a37

20 files changed

Lines changed: 437 additions & 171 deletions

README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -519,14 +519,17 @@ export default antfu(
519519
},
520520
},
521521
{
522-
// Without `files`, they are general rules for all files
522+
// Without `files`, they are general rules for all files (Markdown excluded — see note below)
523523
rules: {
524524
'style/semi': ['error', 'never'],
525525
},
526526
}
527527
)
528528
```
529529

530+
> [!NOTE]
531+
> Rule overrides without an explicit `files` constraint are automatically excluded from Markdown files, via [`composer.setDefaultIgnores`](https://github.com/antfu/eslint-flat-config-utils#composersetdefaultignores). This prevents JS-only rules (e.g. `no-irregular-whitespace`, `perfectionist/sort-imports`) from crashing on `@eslint/markdown`'s `SourceCode`, which doesn't expose JS-specific methods like `getAllComments()`. If you want a rule to apply to Markdown, scope it explicitly with `files: ['**/*.md']`.
532+
530533
We also provided the `overrides` options in each integration to make it easier:
531534

532535
```js

fixtures/eslint.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { antfu } from './src'
1+
import { antfu } from '../src'
22

33
export default antfu(
44
{
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
// This file is generated by ChatGPT
2+
3+
// eslint-disable-next-line no-console
4+
const log = console.log
5+
6+
// Define a class using ES6 class syntax
7+
class Person {
8+
constructor(name, age) {
9+
this.name = name
10+
this.age = age
11+
}
12+
13+
// Define a method within the class
14+
sayHello() {
15+
log(`Hello, my name is ${this.name} and I am ${this.age} years old.`)
16+
}
17+
}
18+
19+
// Create an array of objects
20+
const people = [
21+
new Person('Alice', 30),
22+
new Person('Bob', 25),
23+
new Person('Charlie', 35),
24+
]
25+
26+
// Use the forEach method to iterate over the array
27+
people.forEach((person) => {
28+
person.sayHello()
29+
})
30+
31+
// Use a template literal to create a multiline string
32+
const multilineString = `
33+
This is a multiline string
34+
that spans multiple lines.
35+
`
36+
37+
// Use destructuring assignment to extract values from an object
38+
const { name, age } = people[0]
39+
log(`First person in the array is ${name} and they are ${age} years old.`, multilineString)
40+
41+
// Use the spread operator to create a new array
42+
const numbers = [1, 2, 3]
43+
const newNumbers = [...numbers, 4, 5]
44+
log(newNumbers)
45+
46+
// Use a try-catch block for error handling
47+
try {
48+
// Attempt to parse an invalid JSON string
49+
JSON.parse('invalid JSON')
50+
}
51+
catch (error) {
52+
console.error('Error parsing JSON:', error.message)
53+
}
54+
55+
// Use a ternary conditional operator
56+
const isEven = num => num % 2 === 0
57+
const number = 7
58+
log(`${number} is ${isEven(number) ? 'even' : 'odd'}.`)
59+
60+
// Use a callback function with setTimeout for asynchronous code
61+
setTimeout(() => {
62+
log('This code runs after a delay of 2 seconds.')
63+
}, 2000)
64+
65+
let a, b, c, d, foo
66+
67+
if (a
68+
|| b
69+
|| c || d
70+
|| (d && b)) {
71+
foo()
72+
}

fixtures/output/issue-837/jsx.jsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import React from 'react'
2+
3+
const PATTERN = /\.\d+/g
4+
5+
export function HelloWorld({
6+
greeting = 'hello',
7+
greeted = '"World"',
8+
silent = false,
9+
onMouseOver,
10+
}) {
11+
const [num] = React.useState(() => Math
12+
.floor (Math.random() * 1e+7)
13+
.toString()
14+
.replace(PATTERN, ''))
15+
16+
if (!greeting) {
17+
return null
18+
};
19+
20+
return (
21+
<div className="HelloWorld" title={`You are visitor number ${num}`} onMouseOver={onMouseOver}>
22+
<strong>{ greeting.slice(0, 1).toUpperCase() + greeting.slice(1).toLowerCase() }</strong>
23+
{greeting.endsWith(',')
24+
? ' '
25+
: <span style={{ color: '\grey' }}>", "</span> }
26+
<em>
27+
{ greeted }
28+
</em>
29+
{ (silent) ? '.' : '!'}
30+
</div>
31+
)
32+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
Header
2+
======
3+
4+
_Look,_ code blocks are formatted *too!*
5+
6+
```js
7+
// This should be handled by ESLint instead of Prettier
8+
function identity(x) {
9+
if (foo) {
10+
console.log('bar')
11+
}
12+
}
13+
```
14+
15+
```css
16+
/* This should be handled by Prettier */
17+
.foo { color:red;}
18+
```
19+
20+
Pilot|Airport|Hours
21+
--|:--:|--:
22+
John Doe|SKG|1338
23+
Jane Roe|JFK|314
24+
25+
- - - - - - - - - - - - - - -
26+
27+
+ List
28+
+ with a [link] (/to/somewhere)
29+
+ and [another one]
30+
31+
32+
[another one]: http://example.com 'Example title'
33+
34+
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
35+
Curabitur consectetur maximus risus, sed maximus tellus tincidunt et.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
comma = [
2+
1,
3+
2,
4+
3,
5+
]
6+
7+
[foo]
8+
b = 1
9+
c = "hello"
10+
a = { answer = 42 }
11+
indent = [
12+
1,
13+
2
14+
]
15+
16+
[a-table]
17+
apple.type = "fruit"
18+
apple.skin = "thin"
19+
apple.color = "red"
20+
21+
orange.type = "fruit"
22+
orange.skin = "thick"
23+
orange.color = "orange"

pnpm-lock.yaml

Lines changed: 23 additions & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pnpm-workspace.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ catalogs:
7575
ansis: ^4.2.0
7676
cac: ^7.0.0
7777
eslint-config-flat-gitignore: ^2.3.0
78-
eslint-flat-config-utils: ^3.1.0
78+
eslint-flat-config-utils: ^3.2.0
7979
eslint-merge-processors: ^2.0.0
8080
eslint-plugin-antfu: ^3.2.2
8181
eslint-plugin-command: ^3.5.2

src/configs/markdown.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -53,22 +53,6 @@ export async function markdown(
5353
...overridesMarkdown,
5454
},
5555
},
56-
{
57-
files,
58-
name: 'antfu/markdown/disables/markdown',
59-
rules: {
60-
// Disable rules do not work with markdown sourcecode.
61-
'command/command': 'off',
62-
'no-irregular-whitespace': 'off',
63-
'perfectionist/sort-exports': 'off',
64-
'perfectionist/sort-imports': 'off',
65-
'regexp/no-legacy-features': 'off',
66-
'regexp/no-missing-g-flag': 'off',
67-
'regexp/no-useless-dollar-replacements': 'off',
68-
'regexp/no-useless-flag': 'off',
69-
'style/indent': 'off',
70-
},
71-
},
7256
{
7357
files: [
7458
GLOB_MARKDOWN_CODE,

src/factory.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import {
3939
import { e18e } from './configs/e18e'
4040
import { formatters } from './configs/formatters'
4141
import { regexp } from './configs/regexp'
42+
import { GLOB_MARKDOWN } from './globs'
4243
import { interopDefault, isInEditorEnv } from './utils'
4344

4445
const flatConfigProps = [
@@ -412,6 +413,14 @@ export function antfu(
412413
...userConfigs as any,
413414
)
414415

416+
// Markdown uses the `markdown/gfm` language, whose `SourceCode` lacks JS-only
417+
// methods like `getAllComments`. Without this, any rule override registered
418+
// without a `files` constraint would apply globally and crash on `.md` files.
419+
// See https://github.com/antfu/eslint-config/issues/837.
420+
if (options.markdown ?? true) {
421+
composer = composer.setDefaultIgnores(prev => [...prev, GLOB_MARKDOWN])
422+
}
423+
415424
if (autoRenamePlugins) {
416425
composer = composer
417426
.renamePlugins(defaultPluginRenaming)

0 commit comments

Comments
 (0)