Skip to content

Commit 35d2fe2

Browse files
authored
fix: restore first level jsx AST and tokens (#394)
1 parent 7e59d5e commit 35d2fe2

File tree

14 files changed

+1529
-432
lines changed

14 files changed

+1529
-432
lines changed

package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,11 @@
2626
"typecov": "type-coverage"
2727
},
2828
"devDependencies": {
29-
"@1stg/lib-config": "^6.0.0",
29+
"@1stg/lib-config": "^6.1.0",
3030
"@types/eslint": "^8.4.2",
3131
"@types/eslint-plugin-markdown": "^2.0.0",
32-
"@types/jest": "^27.5.0",
33-
"@types/node": "^17.0.32",
32+
"@types/jest": "^27.5.1",
33+
"@types/node": "^17.0.33",
3434
"@types/react": "^18.0.9",
3535
"@types/unist": "^2.0.6",
3636
"lerna": "^4.0.0",
@@ -69,7 +69,7 @@
6969
"collectCoverage": true,
7070
"coverageThreshold": {
7171
"global": {
72-
"branches": 98,
72+
"branches": 100,
7373
"functions": 100,
7474
"lines": 100,
7575
"statements": 100
@@ -88,7 +88,7 @@
8888
]
8989
},
9090
"typeCoverage": {
91-
"atLeast": 99.93,
91+
"atLeast": 99.95,
9292
"cache": true,
9393
"detail": true,
9494
"ignoreAsAssertion": true,

packages/eslint-mdx/shim.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ declare module 'espree/lib/token-translator' {
5858
token: acorn.Token,
5959
extra: {
6060
// eslint-disable-next-line no-magic-numbers, sonar/max-union-size
61-
ecmaVersion: 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13
61+
ecmaVersion: 'latest' | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13
6262
tokens: EsprimaToken[]
6363
},
6464
): void

packages/eslint-mdx/src/helpers.ts

Lines changed: 85 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,58 +3,17 @@ import fs from 'fs'
33
import path from 'path'
44
import { pathToFileURL } from 'url'
55

6-
import type { SourceLocation } from 'estree'
6+
import type { Position } from 'acorn'
77
import { createSyncFn } from 'synckit'
8-
import type { Node, Position } from 'unist'
8+
import type { Point } from 'unist'
99

1010
import type {
11-
MdxNode,
12-
ValueOf,
11+
NormalPosition,
1312
WorkerOptions,
1413
WorkerParseResult,
1514
WorkerProcessResult,
1615
} from './types'
1716

18-
export const MdxNodeType = {
19-
FLOW_EXPRESSION: 'mdxFlowExpression',
20-
JSX_FLOW_ELEMENT: 'mdxJsxFlowElement',
21-
JSX_TEXT_ELEMENT: 'mdxJsxTextElement',
22-
TEXT_EXPRESSION: 'mdxTextExpression',
23-
JS_ESM: 'mdxjsEsm',
24-
} as const
25-
26-
export type MdxNodeType = ValueOf<typeof MdxNodeType>
27-
28-
export const MDX_NODE_TYPES = [
29-
MdxNodeType.FLOW_EXPRESSION,
30-
MdxNodeType.JSX_FLOW_ELEMENT,
31-
MdxNodeType.JSX_TEXT_ELEMENT,
32-
MdxNodeType.TEXT_EXPRESSION,
33-
MdxNodeType.JS_ESM,
34-
] as const
35-
36-
export const isMdxNode = (node: Node): node is MdxNode =>
37-
MDX_NODE_TYPES.includes(node.type as MdxNodeType)
38-
39-
export interface BaseNode {
40-
type: string
41-
loc: SourceLocation
42-
range: [number, number]
43-
start?: number
44-
end?: number
45-
}
46-
47-
export const normalizePosition = (loc: Position): Omit<BaseNode, 'type'> => {
48-
const start = loc.start.offset
49-
const end = loc.end.offset
50-
return {
51-
range: [start, end],
52-
loc,
53-
start,
54-
end,
55-
}
56-
}
57-
5817
export const last = <T>(items: T[] | readonly T[]) =>
5918
items && items[items.length - 1]
6019

@@ -163,6 +122,7 @@ export const requirePkg = async <T>(
163122
prefix = prefix.endsWith('-') ? prefix : prefix + '-'
164123
packages = [
165124
plugin,
125+
/* istanbul ignore next */
166126
plugin.startsWith('@')
167127
? plugin.replace('/', '/' + prefix)
168128
: prefix + plugin,
@@ -181,6 +141,87 @@ export const requirePkg = async <T>(
181141
throw error
182142
}
183143

144+
/* istanbul ignore next -- used in worker */
145+
export const getPositionAtFactory = (text: string) => {
146+
const lines = text.split('\n')
147+
return (offset: number): Position => {
148+
let currOffset = 0
149+
150+
for (const [index, line_] of lines.entries()) {
151+
const line = index + 1
152+
const nextOffset = currOffset + line_.length
153+
154+
if (nextOffset >= offset) {
155+
return {
156+
line,
157+
column: offset - currOffset,
158+
offset,
159+
}
160+
}
161+
162+
currOffset = nextOffset + 1 // add a line break `\n` offset
163+
}
164+
}
165+
}
166+
167+
export const normalizePosition = ({
168+
start,
169+
end,
170+
text,
171+
}: {
172+
start: Point | { offset: number }
173+
end: Point | { offset: number }
174+
text?: string
175+
}): NormalPosition => {
176+
const startOffset = start.offset
177+
const endOffset = end.offset
178+
const range: [number, number] = [startOffset, endOffset]
179+
const getPositionAt =
180+
text == null
181+
? null
182+
: /* istanbul ignore next -- used in worker */ getPositionAtFactory(text)
183+
return {
184+
start: startOffset,
185+
end: endOffset,
186+
loc: {
187+
start:
188+
/* istanbul ignore next -- used in worker */ 'line' in start
189+
? (start as Position)
190+
: getPositionAt(startOffset),
191+
end:
192+
/* istanbul ignore next -- used in worker */ 'line' in end
193+
? (end as Position)
194+
: getPositionAt(endOffset),
195+
},
196+
range,
197+
}
198+
}
199+
200+
/* istanbul ignore next -- used in worker */
201+
export const prevCharOffsetFactory =
202+
(text: string) =>
203+
(offset: number): number => {
204+
for (let i = offset; i >= 0; i--) {
205+
const char = text[i]
206+
if (/^\S$/.test(char)) {
207+
return i
208+
}
209+
}
210+
}
211+
212+
/* istanbul ignore next -- used in worker */
213+
export const nextCharOffsetFactory = (text: string) => {
214+
const total = text.length
215+
return (offset: number): number => {
216+
for (let i = offset; i <= total; i++) {
217+
const char = text[i]
218+
if (/^\S$/.test(char)) {
219+
return i
220+
}
221+
}
222+
}
223+
}
224+
184225
const workerPath = require.resolve('./worker')
185226

186227
export const performSyncWork = createSyncFn(workerPath) as ((

packages/eslint-mdx/src/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
export * from './helpers'
22
export * from './parser'
3-
export * from './traverse'
43
export * from './types'

packages/eslint-mdx/src/parser.ts

Lines changed: 12 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,20 @@
11
import path from 'path'
22

3-
import type { AST, Linter } from 'eslint'
3+
import type { Linter } from 'eslint'
44
import type { VFileMessage } from 'vfile-message'
55

66
import {
77
arrayify,
8-
isMdxNode,
98
normalizePosition,
109
performSyncWork,
1110
getPhysicalFilename,
1211
} from './helpers'
13-
import { traverse } from './traverse'
1412
import type { ParserOptions, WorkerParseResult } from './types'
1513

1614
export const DEFAULT_EXTENSIONS: readonly string[] = ['.mdx']
1715
export const MARKDOWN_EXTENSIONS: readonly string[] = ['.md']
1816

1917
export class Parser {
20-
// @internal
21-
private _ast: AST.Program
22-
2318
constructor() {
2419
this.parse = this.parse.bind(this)
2520
this.parseForESLint = this.parseForESLint.bind(this)
@@ -79,31 +74,18 @@ export class Parser {
7974
})
8075
}
8176

82-
const { root, tokens } = result
83-
84-
this._ast = {
85-
...normalizePosition(root.position),
86-
type: 'Program',
87-
sourceType,
88-
body: [],
89-
comments: [],
90-
tokens,
77+
const { root, body, comments, tokens } = result
78+
79+
return {
80+
ast: {
81+
...normalizePosition(root.position),
82+
type: 'Program',
83+
sourceType,
84+
body,
85+
comments,
86+
tokens,
87+
},
9188
}
92-
93-
if (isMdx) {
94-
traverse(root, node => {
95-
if (!isMdxNode(node)) {
96-
return
97-
}
98-
99-
const estree = node.data?.estree
100-
101-
this._ast.body.push(...(estree?.body || []))
102-
this._ast.comments.push(...(estree?.comments || []))
103-
})
104-
}
105-
106-
return { ast: this._ast }
10789
}
10890
}
10991

0 commit comments

Comments
 (0)