Skip to content

Commit 8ce78e8

Browse files
authored
Change to determine parser by extension when parsing non-vue files using multiple parser (#124)
* Change to determine parser by extension when parsing non-vue files using multiple parser * update * update
1 parent 184dc09 commit 8ce78e8

File tree

7 files changed

+106
-37
lines changed

7 files changed

+106
-37
lines changed

Diff for: src/common/parser-options.ts

+21-23
Original file line numberDiff line numberDiff line change
@@ -47,42 +47,40 @@ export function isSFCFile(parserOptions: ParserOptions) {
4747
}
4848

4949
/**
50-
* Gets the script parser name from the given SFC document fragment.
50+
* Gets the script parser name from the given parser lang.
5151
*/
5252
export function getScriptParser(
5353
parser: boolean | string | Record<string, string | undefined> | undefined,
54-
doc: VDocumentFragment | null,
55-
block: "script" | "template",
54+
getParserLang: () => string | null | Iterable<string | null>,
5655
): string | undefined {
5756
if (parser && typeof parser === "object") {
58-
if (block === "template") {
59-
const parserForTemplate = parser["<template>"]
60-
if (typeof parserForTemplate === "string") {
61-
return parserForTemplate
62-
}
63-
}
64-
const lang = getScriptLang()
65-
if (lang) {
66-
const parserForLang = parser[lang]
57+
const parserLang = getParserLang()
58+
const parserLangs =
59+
parserLang == null
60+
? []
61+
: typeof parserLang === "string"
62+
? [parserLang]
63+
: parserLang
64+
for (const lang of parserLangs) {
65+
const parserForLang = lang && parser[lang]
6766
if (typeof parserForLang === "string") {
6867
return parserForLang
6968
}
7069
}
7170
return parser.js
7271
}
7372
return typeof parser === "string" ? parser : undefined
73+
}
7474

75-
function getScriptLang() {
76-
if (doc) {
77-
const scripts = doc.children.filter(isScriptElement)
78-
const script =
79-
scripts.length === 2
80-
? scripts.find(isScriptSetupElement)
81-
: scripts[0]
82-
if (script) {
83-
return getLang(script)
84-
}
75+
export function getParserLangFromSFC(doc: VDocumentFragment): string | null {
76+
if (doc) {
77+
const scripts = doc.children.filter(isScriptElement)
78+
const script =
79+
(scripts.length === 2 && scripts.find(isScriptSetupElement)) ||
80+
scripts[0]
81+
if (script) {
82+
return getLang(script)
8583
}
86-
return null
8784
}
85+
return null
8886
}

Diff for: src/html/parser.ts

+12-4
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ import type {
4646
import { IntermediateTokenizer } from "./intermediate-tokenizer"
4747
import type { Tokenizer } from "./tokenizer"
4848
import type { ParserOptions } from "../common/parser-options"
49-
import { isSFCFile, getScriptParser } from "../common/parser-options"
49+
import {
50+
isSFCFile,
51+
getScriptParser,
52+
getParserLangFromSFC,
53+
} from "../common/parser-options"
5054

5155
const DIRECTIVE_NAME = /^(?:v-|[.:@#]).*[^.:@#]$/u
5256
const DT_DD = /^d[dt]$/u
@@ -279,20 +283,24 @@ export class Parser {
279283
this.popElementStackUntil(0)
280284
propagateEndLocation(this.document)
281285

286+
const doc = this.document
287+
282288
const parserOptions = {
283289
...this.baseParserOptions,
284290
parser: getScriptParser(
285291
this.baseParserOptions.parser,
286-
this.document,
287-
"template",
292+
function* () {
293+
yield "<template>"
294+
yield getParserLangFromSFC(doc)
295+
},
288296
),
289297
}
290298
for (const proc of this.postProcessesForScript) {
291299
proc(parserOptions)
292300
}
293301
this.postProcessesForScript = []
294302

295-
return this.document
303+
return doc
296304
}
297305

298306
/**

Diff for: src/index.ts

+22-4
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import { HTMLParser, HTMLTokenizer } from "./html"
1010
import { parseScript, parseScriptElement } from "./script"
1111
import * as services from "./parser-services"
1212
import type { ParserOptions } from "./common/parser-options"
13-
import { getScriptParser } from "./common/parser-options"
13+
import { getScriptParser, getParserLangFromSFC } from "./common/parser-options"
1414
import { parseScriptSetupElements } from "./script-setup"
1515
import { LinesAndColumns } from "./common/lines-and-columns"
1616
import type { VElement } from "./ast"
@@ -64,7 +64,20 @@ export function parseForESLint(
6464
result = parseScript(code, {
6565
...options,
6666
ecmaVersion: options.ecmaVersion || DEFAULT_ECMA_VERSION,
67-
parser: getScriptParser(options.parser, null, "script"),
67+
parser: getScriptParser(options.parser, () => {
68+
const ext = (
69+
path
70+
.extname(options.filePath || "unknown.js")
71+
.toLowerCase() || ""
72+
)
73+
// remove dot
74+
.slice(1)
75+
if (/^[jt]sx$/u.test(ext)) {
76+
return [ext, ext.slice(0, -1)]
77+
}
78+
79+
return ext
80+
}),
6881
})
6982
document = null
7083
locationCalculator = null
@@ -94,7 +107,9 @@ export function parseForESLint(
94107
? Object.assign(template, concreteInfo)
95108
: undefined
96109

97-
const scriptParser = getScriptParser(options.parser, rootAST, "script")
110+
const scriptParser = getScriptParser(options.parser, () =>
111+
getParserLangFromSFC(rootAST),
112+
)
98113
let scriptSetup: VElement | undefined
99114
if (skipParsingScript || !scripts.length) {
100115
result = parseScript("", {
@@ -126,7 +141,10 @@ export function parseForESLint(
126141
const styles = rootAST.children.filter(isStyleElement)
127142
parseStyleElements(styles, locationCalculator, {
128143
...options,
129-
parser: getScriptParser(options.parser, rootAST, "template"),
144+
parser: getScriptParser(options.parser, function* () {
145+
yield "<template>"
146+
yield getParserLangFromSFC(rootAST)
147+
}),
130148
})
131149
}
132150

Diff for: test/fixtures/ast/filters-opt-filter-off-babel/ast.json

+12-6
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@
1010
"end": {
1111
"line": 1,
1212
"column": 0
13-
}
13+
},
14+
"filename": "source.vue"
1415
},
1516
"range": [
1617
0,
@@ -144,7 +145,8 @@
144145
"end": {
145146
"line": 2,
146147
"column": 22
147-
}
148+
},
149+
"filename": "source.vue"
148150
},
149151
"range": [
150152
23,
@@ -162,7 +164,8 @@
162164
"end": {
163165
"line": 2,
164166
"column": 15
165-
}
167+
},
168+
"filename": "source.vue"
166169
},
167170
"range": [
168171
23,
@@ -183,7 +186,8 @@
183186
"end": {
184187
"line": 2,
185188
"column": 22
186-
}
189+
},
190+
"filename": "source.vue"
187191
},
188192
"range": [
189193
30,
@@ -206,7 +210,8 @@
206210
"end": {
207211
"line": 2,
208212
"column": 15
209-
}
213+
},
214+
"filename": "source.vue"
210215
},
211216
"range": [
212217
23,
@@ -229,7 +234,8 @@
229234
"end": {
230235
"line": 2,
231236
"column": 22
232-
}
237+
},
238+
"filename": "source.vue"
233239
},
234240
"range": [
235241
30,

Diff for: test/fixtures/typed.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
interface Data {
2+
greeting: string
3+
}
4+
5+
export default {
6+
data(): Data {
7+
return {greeting: "Hello"}
8+
},
9+
}

Diff for: test/fixtures/typed.tsx

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
interface Data {
2+
greeting: string
3+
}
4+
5+
export default {
6+
data(): Data {
7+
return {greeting: "Hello"}
8+
},
9+
}

Diff for: test/index.js

+21
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,27 @@ describe("Basic tests", () => {
291291

292292
assert.deepStrictEqual(messages, [])
293293
})
294+
295+
it("should notify no error with multiple parser with '@typescript-eslint/parser'", async () => {
296+
const cli = new ESLint({
297+
cwd: FIXTURE_DIR,
298+
overrideConfig: {
299+
env: { es6: true, node: true },
300+
parser: PARSER_PATH,
301+
parserOptions: {
302+
parser: {
303+
ts: "@typescript-eslint/parser",
304+
},
305+
},
306+
rules: { semi: ["error", "never"] },
307+
},
308+
useEslintrc: false,
309+
})
310+
const report = await cli.lintFiles(["typed.ts", "typed.tsx"])
311+
312+
assert.deepStrictEqual(report[0].messages, [])
313+
assert.deepStrictEqual(report[1].messages, [])
314+
})
294315
}
295316
})
296317

0 commit comments

Comments
 (0)