Skip to content

Commit

Permalink
fix: restore first level jsx AST and tokens (#394)
Browse files Browse the repository at this point in the history
  • Loading branch information
JounQin authored May 14, 2022
1 parent 7e59d5e commit 35d2fe2
Show file tree
Hide file tree
Showing 14 changed files with 1,529 additions and 432 deletions.
10 changes: 5 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,11 @@
"typecov": "type-coverage"
},
"devDependencies": {
"@1stg/lib-config": "^6.0.0",
"@1stg/lib-config": "^6.1.0",
"@types/eslint": "^8.4.2",
"@types/eslint-plugin-markdown": "^2.0.0",
"@types/jest": "^27.5.0",
"@types/node": "^17.0.32",
"@types/jest": "^27.5.1",
"@types/node": "^17.0.33",
"@types/react": "^18.0.9",
"@types/unist": "^2.0.6",
"lerna": "^4.0.0",
Expand Down Expand Up @@ -69,7 +69,7 @@
"collectCoverage": true,
"coverageThreshold": {
"global": {
"branches": 98,
"branches": 100,
"functions": 100,
"lines": 100,
"statements": 100
Expand All @@ -88,7 +88,7 @@
]
},
"typeCoverage": {
"atLeast": 99.93,
"atLeast": 99.95,
"cache": true,
"detail": true,
"ignoreAsAssertion": true,
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-mdx/shim.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ declare module 'espree/lib/token-translator' {
token: acorn.Token,
extra: {
// eslint-disable-next-line no-magic-numbers, sonar/max-union-size
ecmaVersion: 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13
ecmaVersion: 'latest' | 3 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13
tokens: EsprimaToken[]
},
): void
Expand Down
129 changes: 85 additions & 44 deletions packages/eslint-mdx/src/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,58 +3,17 @@ import fs from 'fs'
import path from 'path'
import { pathToFileURL } from 'url'

import type { SourceLocation } from 'estree'
import type { Position } from 'acorn'
import { createSyncFn } from 'synckit'
import type { Node, Position } from 'unist'
import type { Point } from 'unist'

import type {
MdxNode,
ValueOf,
NormalPosition,
WorkerOptions,
WorkerParseResult,
WorkerProcessResult,
} from './types'

export const MdxNodeType = {
FLOW_EXPRESSION: 'mdxFlowExpression',
JSX_FLOW_ELEMENT: 'mdxJsxFlowElement',
JSX_TEXT_ELEMENT: 'mdxJsxTextElement',
TEXT_EXPRESSION: 'mdxTextExpression',
JS_ESM: 'mdxjsEsm',
} as const

export type MdxNodeType = ValueOf<typeof MdxNodeType>

export const MDX_NODE_TYPES = [
MdxNodeType.FLOW_EXPRESSION,
MdxNodeType.JSX_FLOW_ELEMENT,
MdxNodeType.JSX_TEXT_ELEMENT,
MdxNodeType.TEXT_EXPRESSION,
MdxNodeType.JS_ESM,
] as const

export const isMdxNode = (node: Node): node is MdxNode =>
MDX_NODE_TYPES.includes(node.type as MdxNodeType)

export interface BaseNode {
type: string
loc: SourceLocation
range: [number, number]
start?: number
end?: number
}

export const normalizePosition = (loc: Position): Omit<BaseNode, 'type'> => {
const start = loc.start.offset
const end = loc.end.offset
return {
range: [start, end],
loc,
start,
end,
}
}

export const last = <T>(items: T[] | readonly T[]) =>
items && items[items.length - 1]

Expand Down Expand Up @@ -163,6 +122,7 @@ export const requirePkg = async <T>(
prefix = prefix.endsWith('-') ? prefix : prefix + '-'
packages = [
plugin,
/* istanbul ignore next */
plugin.startsWith('@')
? plugin.replace('/', '/' + prefix)
: prefix + plugin,
Expand All @@ -181,6 +141,87 @@ export const requirePkg = async <T>(
throw error
}

/* istanbul ignore next -- used in worker */
export const getPositionAtFactory = (text: string) => {
const lines = text.split('\n')
return (offset: number): Position => {
let currOffset = 0

for (const [index, line_] of lines.entries()) {
const line = index + 1
const nextOffset = currOffset + line_.length

if (nextOffset >= offset) {
return {
line,
column: offset - currOffset,
offset,
}
}

currOffset = nextOffset + 1 // add a line break `\n` offset
}
}
}

export const normalizePosition = ({
start,
end,
text,
}: {
start: Point | { offset: number }
end: Point | { offset: number }
text?: string
}): NormalPosition => {
const startOffset = start.offset
const endOffset = end.offset
const range: [number, number] = [startOffset, endOffset]
const getPositionAt =
text == null
? null
: /* istanbul ignore next -- used in worker */ getPositionAtFactory(text)
return {
start: startOffset,
end: endOffset,
loc: {
start:
/* istanbul ignore next -- used in worker */ 'line' in start
? (start as Position)
: getPositionAt(startOffset),
end:
/* istanbul ignore next -- used in worker */ 'line' in end
? (end as Position)
: getPositionAt(endOffset),
},
range,
}
}

/* istanbul ignore next -- used in worker */
export const prevCharOffsetFactory =
(text: string) =>
(offset: number): number => {
for (let i = offset; i >= 0; i--) {
const char = text[i]
if (/^\S$/.test(char)) {
return i
}
}
}

/* istanbul ignore next -- used in worker */
export const nextCharOffsetFactory = (text: string) => {
const total = text.length
return (offset: number): number => {
for (let i = offset; i <= total; i++) {
const char = text[i]
if (/^\S$/.test(char)) {
return i
}
}
}
}

const workerPath = require.resolve('./worker')

export const performSyncWork = createSyncFn(workerPath) as ((
Expand Down
1 change: 0 additions & 1 deletion packages/eslint-mdx/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from './helpers'
export * from './parser'
export * from './traverse'
export * from './types'
42 changes: 12 additions & 30 deletions packages/eslint-mdx/src/parser.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
import path from 'path'

import type { AST, Linter } from 'eslint'
import type { Linter } from 'eslint'
import type { VFileMessage } from 'vfile-message'

import {
arrayify,
isMdxNode,
normalizePosition,
performSyncWork,
getPhysicalFilename,
} from './helpers'
import { traverse } from './traverse'
import type { ParserOptions, WorkerParseResult } from './types'

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

export class Parser {
// @internal
private _ast: AST.Program

constructor() {
this.parse = this.parse.bind(this)
this.parseForESLint = this.parseForESLint.bind(this)
Expand Down Expand Up @@ -79,31 +74,18 @@ export class Parser {
})
}

const { root, tokens } = result

this._ast = {
...normalizePosition(root.position),
type: 'Program',
sourceType,
body: [],
comments: [],
tokens,
const { root, body, comments, tokens } = result

return {
ast: {
...normalizePosition(root.position),
type: 'Program',
sourceType,
body,
comments,
tokens,
},
}

if (isMdx) {
traverse(root, node => {
if (!isMdxNode(node)) {
return
}

const estree = node.data?.estree

this._ast.body.push(...(estree?.body || []))
this._ast.comments.push(...(estree?.comments || []))
})
}

return { ast: this._ast }
}
}

Expand Down
Loading

0 comments on commit 35d2fe2

Please sign in to comment.