Skip to content

Commit c52039c

Browse files
authored
feat: fix incorrect node loc (#288)
* feat: fix incorrect node loc this causes issue with `react/no-unescaped-entities` before so now `mdx/no-unescaped-entities` and `eslint-plugin-react` dep can be removed! fix #287 * ci: try codesandbox for releasing testing versions
1 parent 52d712a commit c52039c

File tree

18 files changed

+48
-302
lines changed

18 files changed

+48
-302
lines changed

.codesandbox/ci.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"packages": [
3+
"packages/*"
4+
],
5+
"sandboxes": []
6+
}

README.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
- [Parser Options](#parser-options)
3737
- [Rules](#rules)
3838
- [mdx/no-jsx-html-comments](#mdxno-jsx-html-comments)
39-
- [mdx/no-unescaped-entities](#mdxno-unescaped-entities)
4039
- [mdx/no-unused-expressions](#mdxno-unused-expressions)
4140
- [mdx/remark](#mdxremark)
4241
- [Prettier Integration](#prettier-integration)
@@ -183,10 +182,6 @@ npm i -D eslint-plugin-mdx
183182

184183
_Fixable_: HTML style comments in jsx block is invalid, this rule will help you to fix it by transforming it to JSX style comments.
185184

186-
### mdx/no-unescaped-entities
187-
188-
Inline JSX like `Inline <Component />` is supported by [MDX][], but rule `react/no-unescaped-entities` from [eslint-plugin-react][] is incompatible with it, `mdx/no-unescaped-entities` is the replacement, so make sure that you've turned off the original `no-unescaped-entities` rule.
189-
190185
### mdx/no-unused-expressions
191186

192187
[MDX][] can render `jsx` block automatically without exporting them, but [ESLint][] will report `no-unused-expressions` issue which could be unexpected, this rule is the replacement, so make sure that you've turned off the original `no-unused-expressions` rule.

packages/eslint-mdx/README.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
- [Parser Options](#parser-options)
3737
- [Rules](#rules)
3838
- [mdx/no-jsx-html-comments](#mdxno-jsx-html-comments)
39-
- [mdx/no-unescaped-entities](#mdxno-unescaped-entities)
4039
- [mdx/no-unused-expressions](#mdxno-unused-expressions)
4140
- [mdx/remark](#mdxremark)
4241
- [Prettier Integration](#prettier-integration)
@@ -183,10 +182,6 @@ npm i -D eslint-plugin-mdx
183182

184183
_Fixable_: HTML style comments in jsx block is invalid, this rule will help you to fix it by transforming it to JSX style comments.
185184

186-
### mdx/no-unescaped-entities
187-
188-
Inline JSX like `Inline <Component />` is supported by [MDX][], but rule `react/no-unescaped-entities` from [eslint-plugin-react][] is incompatible with it, `mdx/no-unescaped-entities` is the replacement, so make sure that you've turned off the original `no-unescaped-entities` rule.
189-
190185
### mdx/no-unused-expressions
191186

192187
[MDX][] can render `jsx` block automatically without exporting them, but [ESLint][] will report `no-unused-expressions` issue which could be unexpected, this rule is the replacement, so make sure that you've turned off the original `no-unused-expressions` rule.

packages/eslint-mdx/src/helpers.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,23 +112,34 @@ export const restoreNodeLocation = <T>(
112112
const start = range[0] + offset
113113
const end = range[1] + offset
114114

115+
const restoredStartLine = startLine + startLoc.line
116+
const restoredEndLine = startLine + endLoc.line
117+
115118
return Object.assign(node, {
116119
start,
117120
end,
118121
range: [start, end],
119122
loc: {
120123
start: {
121-
line: startLine + startLoc.line,
122-
column: startLoc.column,
124+
line: restoredStartLine,
125+
column: startLoc.column + (restoredStartLine === 1 ? offset : 0),
123126
},
124127
end: {
125-
line: startLine + endLoc.line,
126-
column: endLoc.column,
128+
line: restoredEndLine,
129+
column: endLoc.column + (restoredEndLine === 1 ? offset : 0),
127130
},
128131
},
129132
})
130133
}
131134

135+
export const arrayify = <T, R = T extends Array<infer S> ? S : T>(
136+
...args: T[]
137+
) =>
138+
args.reduce<R[]>((arr, curr) => {
139+
arr.push(...(Array.isArray(curr) ? curr : curr == null ? [] : [curr]))
140+
return arr
141+
}, [])
142+
132143
export const first = <T>(items: T[] | readonly T[]) => items && items[0]
133144

134145
export const last = <T>(items: T[] | readonly T[]) =>

packages/eslint-mdx/src/parser.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import unified from 'unified'
88
import type { Node, Parent } from 'unist'
99

1010
import {
11+
arrayify,
1112
hasProperties,
1213
isJsxNode,
1314
last,
@@ -154,7 +155,6 @@ export class Parser {
154155
return this.parseForESLint(code, options).ast
155156
}
156157

157-
// eslint-disable-next-line sonarjs/cognitive-complexity
158158
parseForESLint(code: string, options: ParserOptions) {
159159
const extname = path.extname(options.filePath)
160160
const isMdx = DEFAULT_EXTENSIONS.concat(options.extensions || []).includes(
@@ -190,9 +190,9 @@ export class Parser {
190190
return
191191
}
192192

193-
let normalized = this.normalizeJsxNode(node, parent, options)
194-
normalized = Array.isArray(normalized) ? normalized : [normalized]
195-
for (const normalizedNode of normalized) {
193+
for (const normalizedNode of arrayify(
194+
this.normalizeJsxNode(node, parent, options),
195+
)) {
196196
this._nodeToAst(normalizedNode, options)
197197
}
198198
},

packages/eslint-mdx/src/traverse.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { Node, Parent } from 'unist'
22

3-
import { last } from './helpers'
3+
import { arrayify, last } from './helpers'
44
import { parser } from './parser'
55
import {
66
isCloseTag,
@@ -75,8 +75,7 @@ export class Traverse {
7575
}
7676
try {
7777
// fix #138
78-
const nodes = parser.normalizeJsxNode(node, parent)
79-
jsxNodes.push(...(Array.isArray(nodes) ? nodes : [nodes]))
78+
jsxNodes.push(...arrayify(parser.normalizeJsxNode(node, parent)))
8079
} catch {
8180
// #272 related
8281
/* istanbul ignore else */

packages/eslint-plugin-mdx/README.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,6 @@
3636
- [Parser Options](#parser-options)
3737
- [Rules](#rules)
3838
- [mdx/no-jsx-html-comments](#mdxno-jsx-html-comments)
39-
- [mdx/no-unescaped-entities](#mdxno-unescaped-entities)
4039
- [mdx/no-unused-expressions](#mdxno-unused-expressions)
4140
- [mdx/remark](#mdxremark)
4241
- [Prettier Integration](#prettier-integration)
@@ -183,10 +182,6 @@ npm i -D eslint-plugin-mdx
183182

184183
_Fixable_: HTML style comments in jsx block is invalid, this rule will help you to fix it by transforming it to JSX style comments.
185184

186-
### mdx/no-unescaped-entities
187-
188-
Inline JSX like `Inline <Component />` is supported by [MDX][], but rule `react/no-unescaped-entities` from [eslint-plugin-react][] is incompatible with it, `mdx/no-unescaped-entities` is the replacement, so make sure that you've turned off the original `no-unescaped-entities` rule.
189-
190185
### mdx/no-unused-expressions
191186

192187
[MDX][] can render `jsx` block automatically without exporting them, but [ESLint][] will report `no-unused-expressions` issue which could be unexpected, this rule is the replacement, so make sure that you've turned off the original `no-unused-expressions` rule.

packages/eslint-plugin-mdx/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
"dependencies": {
3636
"cosmiconfig": "^7.0.0",
3737
"eslint-mdx": "^1.10.0",
38-
"eslint-plugin-react": "^7.22.0",
3938
"remark-mdx": "^1.6.22",
4039
"remark-parse": "^8.0.3",
4140
"remark-stringify": "^8.1.1",

packages/eslint-plugin-mdx/src/configs/recommended.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@ export const recommended: Linter.Config = {
99
...base,
1010
rules: {
1111
'mdx/no-jsx-html-comments': 2,
12-
'mdx/no-unescaped-entities': 1,
1312
'mdx/no-unused-expressions': 2,
1413
'mdx/remark': 1,
1514
'no-unused-expressions': 0,
16-
'react/no-unescaped-entities': 0,
1715
},
1816
}
1917

packages/eslint-plugin-mdx/src/rules/helpers.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ import path from 'path'
22

33
import { cosmiconfigSync } from 'cosmiconfig'
44
import type { CosmiconfigResult } from 'cosmiconfig/dist/types'
5+
import { arrayify } from 'eslint-mdx'
56
import remarkMdx from 'remark-mdx'
67
import remarkParse from 'remark-parse'
78
import remarkStringify from 'remark-stringify'
89
import unified from 'unified'
910

10-
import type { RemarkConfig } from './types'
11+
import type { RemarkConfig, RemarkPlugin } from './types'
1112

1213
export const requirePkg = <T>(
1314
plugin: string,
@@ -90,9 +91,10 @@ export const getRemarkProcessor = (searchFrom: string, isMdx: boolean) => {
9091

9192
return plugins
9293
.reduce((processor, pluginWithSettings) => {
93-
const [plugin, ...pluginSettings] = Array.isArray(pluginWithSettings)
94-
? pluginWithSettings
95-
: [pluginWithSettings]
94+
const [plugin, ...pluginSettings] = arrayify(pluginWithSettings) as [
95+
RemarkPlugin,
96+
...unknown[]
97+
]
9698
return processor.use(
9799
/* istanbul ignore next */
98100
typeof plugin === 'string'

0 commit comments

Comments
 (0)