Skip to content

Commit 6ca246f

Browse files
committed
refactor: totally replace no-unescaped-entities, default warning
lot of code/type refactor
1 parent dca8633 commit 6ca246f

18 files changed

+286
-158
lines changed

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,9 +58,11 @@ npm i -D @rxts/eslint-plugin-mdx
5858
"plugins": ["@rxts/mdx"],
5959
"rules": {
6060
"@rxts/mdx/no-jsx-html-comments": 2,
61+
"@rxts/mdx/no-unescaped-entities": 1,
6162
"@rxts/mdx/no-unused-expressions": 2,
6263
"no-unused-expressions": 0,
63-
"react/react-in-jsx-scope": 0
64+
"react/react-in-jsx-scope": 0,
65+
"react/no-unescaped-entities": 0
6466
}
6567
}
6668
]
@@ -101,9 +103,13 @@ This parser/plugin should only affects `.mdx` files, and `overrides` in `shared
101103

102104
HTML style comments in jsx block is invalid, this rule will help you to fix it by transforming it to JSX style comments.
103105

106+
### @rxts/mdx/no-unescaped-entities
107+
108+
Inline JSX like `Inline <Component />` is supported by [MDX], but rule `react/no-unescaped-entities` from [eslint-plugin-react] is incompatible with it, `@rxts/mdx/no-unescaped-entities` is the replacement.
109+
104110
### @rxts/mdx/no-unused-expressions
105111

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

108114
## Limitation
109115

@@ -120,6 +126,7 @@ Detailed changes for each release are documented in [CHANGELOG.md](./CHANGELOG.m
120126
[MIT]
121127

122128
[eslint]: https://eslint.org
129+
[eslint-plugin-react]: https://github.com/yannickcr/eslint-plugin-react
123130
[mdx]: https://github.com/mdx-js/mdx
124131
[mit]: http://opensource.org/licenses/MIT
125132
[markdownlint]: https://github.com/markdownlint/markdownlint

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@rxts/eslint-plugin-mdx",
3-
"version": "0.6.0",
3+
"version": "0.7.0",
44
"description": "ESLint Parser/Plugin for MDX",
55
"repository": "[email protected]:rx-ts/eslint-plugin-mdx.git",
66
"author": "JounQin <[email protected]>",

src/helper.ts

Lines changed: 67 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { Position } from 'unist'
1+
import { isComment, COMMENT_CONTENT_REGEX } from './regexp'
2+
import { Comment } from './types'
3+
4+
import { Position, Node, Parent } from 'unist'
25
import { AST } from 'eslint'
36
// `SourceLocation` is not exported from estree, but it is actually working
47
// eslint-disable-next-line import/named
@@ -78,3 +81,66 @@ export const first = <T>(items: T[] | ReadonlyArray<T>) => items && items[0]
7881

7982
export const last = <T>(items: T[] | ReadonlyArray<T>) =>
8083
items && items[items.length - 1]
84+
85+
export const normalizeJsxNode = (node: Node, parent?: Parent) => {
86+
const value = node.value as string
87+
88+
if (isComment(value)) {
89+
return node
90+
}
91+
92+
const matched = value.match(COMMENT_CONTENT_REGEX)
93+
94+
if (!matched) {
95+
return node
96+
}
97+
98+
const comments: Comment[] = []
99+
const {
100+
position: {
101+
start: { line, column, offset: startOffset },
102+
},
103+
} = node
104+
105+
return Object.assign(node, {
106+
data: {
107+
...node.data,
108+
jsxType: 'JSXElementWithHTMLComments',
109+
comments,
110+
// jsx in paragraph is considered as plain html in mdx, what means html style comments are valid
111+
// TODO: in this case, jsx style comments could be a mistake
112+
inline: !!parent && parent.type !== 'root',
113+
},
114+
value: value.replace(
115+
COMMENT_CONTENT_REGEX,
116+
(matched: string, $0: string, $1: string, $2: string, offset: number) => {
117+
const endOffset = offset + matched.length
118+
const startLines = value.slice(0, offset).split('\n')
119+
const endLines = value.slice(0, endOffset).split('\n')
120+
const fixed = `{/${'*'.repeat($0.length - 2)}${$1}${'*'.repeat(
121+
$2.length - 2,
122+
)}/}`
123+
const startLineOffset = startLines.length - 1
124+
const endLineOffset = endLines.length - 1
125+
comments.push({
126+
fixed,
127+
loc: {
128+
start: {
129+
line: line + startLineOffset,
130+
column:
131+
last(startLines).length + (startLineOffset ? 0 : column - 1),
132+
offset: startOffset + offset,
133+
},
134+
end: {
135+
line: line + endLineOffset - 1,
136+
column: last(endLines).length + (endLineOffset ? 0 : column - 1),
137+
offset: startOffset + endOffset,
138+
},
139+
},
140+
origin: matched,
141+
})
142+
return fixed
143+
},
144+
),
145+
})
146+
}

src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import path from 'path'
22

33
export * from './helper'
4-
export * from './normalizer'
54
export * from './parser'
65
export * from './regexp'
76
export * from './rules'
@@ -13,7 +12,7 @@ export const configs = {
1312
plugins: ['@rxts/mdx'],
1413
rules: {
1514
'@rxts/mdx/no-jsx-html-comments': 2,
16-
'@rxts/mdx/no-unescaped-entities': 2,
15+
'@rxts/mdx/no-unescaped-entities': 1,
1716
'@rxts/mdx/no-unused-expressions': 2,
1817
'no-unused-expressions': 0,
1918
'react/no-unescaped-entities': 0,

src/normalizer.ts

Lines changed: 0 additions & 76 deletions
This file was deleted.

src/parser.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@ import remarkMdx from 'remark-mdx'
66
import remarkParse from 'remark-parse'
77
import unified from 'unified'
88

9-
import { normalizeJsxNode } from './normalizer'
10-
import { normalizePosition, restoreNodeLocation } from './helper'
9+
import {
10+
normalizeJsxNode,
11+
normalizePosition,
12+
restoreNodeLocation,
13+
} from './helper'
1114
import { isComment } from './regexp'
1215
import { traverse } from './traverse'
1316

src/regexp.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,13 @@ const attributeValue =
1919
const attribute =
2020
'(?:\\s+' + attributeName + '(?:\\s*=\\s*' + attributeValue + ')?)'
2121

22-
const openTag = '<[A-Za-z]*[A-Za-z0-9\\.\\-]*' + attribute + '*\\s*>'
23-
const closeTag = '<\\s*\\/[A-Za-z]*[A-Za-z0-9\\.\\-]*\\s*>'
24-
const selfClosingTag = '<[A-Za-z]*[A-Za-z0-9\\.\\-]*' + attribute + '*\\s*\\/?>'
25-
const comment = '<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->'
26-
const commentOpen = '(<!---*)'
27-
const commentClose = '(-*-->)'
22+
export const openTag = '<[A-Za-z]*[A-Za-z0-9\\.\\-]*' + attribute + '*\\s*>'
23+
export const closeTag = '<\\s*\\/[A-Za-z]*[A-Za-z0-9\\.\\-]*\\s*>'
24+
export const selfClosingTag =
25+
'<[A-Za-z]*[A-Za-z0-9\\.\\-]*' + attribute + '*\\s*\\/?>'
26+
export const comment = '<!---->|<!--(?:-?[^>-])(?:-?[^-])*-->'
27+
export const commentOpen = '(<!---*)'
28+
export const commentClose = '(-*-->)'
2829

2930
export const OPEN_TAG_REGEX = new RegExp(`^(?:${openTag})$`)
3031
export const CLOSE_TAG_REGEX = new RegExp(`^(?:${closeTag})$`)

src/rules/helper.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { JsxNode, JsxType, JsxTypes } from './types'
2+
3+
export const JSX_TYPES: JsxTypes = ['JSXElement', 'JSXFragment']
4+
5+
export const isJsxNode = (node: { type: string }): node is JsxNode =>
6+
JSX_TYPES.includes(node.type as JsxType)

src/rules/index.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import { noJsxHtmlComments } from './no-jsx-html-comments'
22
import { noUnEscapedEntities } from './no-unescaped-entities'
33
import { noUnUsedExpressions } from './no-unused-expressions'
44

5-
export { noJsxHtmlComments, noUnUsedExpressions }
5+
export * from './helper'
6+
export * from './types'
7+
8+
export { noJsxHtmlComments, noUnEscapedEntities, noUnUsedExpressions }
69

710
export const rules = {
811
'no-jsx-html-comments': noJsxHtmlComments,

src/rules/no-jsx-html-comments.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
import { Comment } from '../normalizer'
1+
import { Comment } from '../types'
22

3-
import { ExpressionStatementWithParent, JSX_TYPES, JsxType } from './types'
3+
import { JSX_TYPES } from './helper'
4+
import { ExpressionStatementWithParent, JsxType } from './types'
45

56
import { Rule } from 'eslint'
67
import { Node } from 'unist'

0 commit comments

Comments
 (0)