Skip to content

Commit 342f661

Browse files
authored
Improve handling of tsx (#37)
* Improve handling of tsx * update
1 parent fcef867 commit 342f661

File tree

4 files changed

+85
-32
lines changed

4 files changed

+85
-32
lines changed

src/context/resolve-parser/espree.ts

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,7 @@
1-
import Module from "module"
1+
import { createRequire } from "module"
22
import path from "path"
33
import type { ESLintCustomParser } from "../../types"
44

5-
const createRequire: (filename: string) => (modName: string) => any =
6-
// Added in v12.2.0
7-
Module.createRequire ||
8-
// Added in v10.12.0, but deprecated in v12.2.0.
9-
// @ts-expect-error -- old type
10-
Module.createRequireFromPath ||
11-
// Polyfill - This is not executed on the tests on node@>=10.
12-
/* istanbul ignore next */
13-
((modName) => {
14-
const mod = new Module(modName)
15-
16-
mod.filename = modName
17-
mod.paths = (Module as any)._nodeModulePaths(path.dirname(modName))
18-
;(mod as any)._compile("module.exports = require;", modName)
19-
return mod.exports
20-
})
21-
225
let espreeCache: ESLintCustomParser | null = null
236

247
/** Checks if given path is linter path */

src/parser/script.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import type { Context } from "../context"
2-
import fs from "fs"
32
import { debug } from "../debug"
43
import type { ParserOptionsContext } from "../context/parser-options"
54
import type { ESLintExtendedProgram } from "../types"
6-
5+
import { tsPatch } from "./ts-patch"
6+
import type { ParserOptions } from "@typescript-eslint/types"
77
/**
88
* Parse for script
99
*/
@@ -14,23 +14,22 @@ export function parseScript(
1414
): ESLintExtendedProgram {
1515
const parser = parserOptions.getParser()
1616

17-
let removeFile: string | null = null
17+
let patchResult
1818

1919
try {
20-
const scriptParserOptions = { ...parserOptions.parserOptions }
20+
const scriptParserOptions: ParserOptions = {
21+
...parserOptions.parserOptions,
22+
}
23+
scriptParserOptions.ecmaFeatures = {
24+
...(scriptParserOptions.ecmaFeatures || {}),
25+
jsx: true,
26+
}
2127
if (
2228
parserOptions.isTypeScript() &&
2329
scriptParserOptions.filePath &&
2430
scriptParserOptions.project
2531
) {
26-
scriptParserOptions.filePath += ".tsx"
27-
if (!fs.existsSync(scriptParserOptions.filePath)) {
28-
fs.writeFileSync(
29-
scriptParserOptions.filePath,
30-
"/* temp for astro-eslint-parser */",
31-
)
32-
removeFile = scriptParserOptions.filePath
33-
}
32+
patchResult = tsPatch(scriptParserOptions)
3433
}
3534
const result =
3635
parser.parseForESLint?.(code, scriptParserOptions) ??
@@ -50,6 +49,6 @@ ${code}`,
5049
)
5150
throw e
5251
} finally {
53-
if (removeFile) fs.unlinkSync(removeFile)
52+
patchResult?.terminate()
5453
}
5554
}

src/parser/ts-patch.ts

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { createRequire } from "module"
2+
import type { ParserOptions } from "@typescript-eslint/types"
3+
import path from "path"
4+
import fs from "fs"
5+
import type { ScriptKind } from "typescript"
6+
type TS = {
7+
ScriptKind: typeof ScriptKind
8+
ensureScriptKind?: (fileName: string, ...args: any[]) => ScriptKind
9+
getScriptKindFromFileName?: (fileName: string, ...args: any[]) => ScriptKind
10+
}
11+
12+
export type PatchTerminate = { terminate: () => void }
13+
14+
/**
15+
* Apply a patch to parse .astro files as TSX.
16+
*/
17+
export function tsPatch(
18+
scriptParserOptions: ParserOptions,
19+
): PatchTerminate | null {
20+
try {
21+
// Apply a patch to parse .astro files as TSX.
22+
const cwd = process.cwd()
23+
const relativeTo = path.join(cwd, "__placeholder__.js")
24+
const ts: TS = createRequire(relativeTo)("typescript")
25+
26+
const { ensureScriptKind, getScriptKindFromFileName } = ts
27+
if (
28+
typeof ensureScriptKind === "function" &&
29+
typeof getScriptKindFromFileName === "function"
30+
) {
31+
ts.ensureScriptKind = function (fileName: string, ...args: any[]) {
32+
if (fileName.endsWith(".astro")) {
33+
return ts.ScriptKind.TSX
34+
}
35+
return ensureScriptKind.call(this, fileName, ...args)
36+
}
37+
ts.getScriptKindFromFileName = function (
38+
fileName: string,
39+
...args: any[]
40+
) {
41+
if (fileName.endsWith(".astro")) {
42+
return ts.ScriptKind.TSX
43+
}
44+
return getScriptKindFromFileName.call(this, fileName, ...args)
45+
}
46+
return {
47+
terminate() {
48+
ts.ensureScriptKind = ensureScriptKind
49+
ts.getScriptKindFromFileName = getScriptKindFromFileName
50+
},
51+
}
52+
}
53+
} catch {
54+
// ignore
55+
}
56+
57+
// If the patch cannot be applied, create a tsx file and parse it.
58+
const tsxFilePath = `${scriptParserOptions.filePath}.tsx`
59+
scriptParserOptions.filePath = tsxFilePath
60+
if (!fs.existsSync(tsxFilePath)) {
61+
fs.writeFileSync(tsxFilePath, "/* temp for astro-eslint-parser */")
62+
63+
return {
64+
terminate() {
65+
fs.unlinkSync(tsxFilePath)
66+
},
67+
}
68+
}
69+
70+
return null
71+
}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
22
"include": [
3-
"**/*.astro.tsx"
3+
"**/*.astro"
44
]
55
}

0 commit comments

Comments
 (0)