Skip to content

Commit 9720b51

Browse files
committed
add support for custom template tokenizers
1 parent d900ec2 commit 9720b51

File tree

3 files changed

+53
-1
lines changed

3 files changed

+53
-1
lines changed

src/common/parser-options.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
import * as path from "path"
2+
import type { IntermediateToken } from "../html/intermediate-tokenizer"
23
import type { VDocumentFragment } from "../ast"
34
import { getLang, isScriptElement, isScriptSetupElement } from "./ast-utils"
45

6+
interface TemplateTokenizer {
7+
nextToken(): IntermediateToken
8+
}
9+
10+
interface TemplateTokenizerConstructor {
11+
new (
12+
templateText: string,
13+
source: string,
14+
options: { startingLine: number; startingColumn: number },
15+
): TemplateTokenizer
16+
}
17+
518
export interface ParserOptions {
619
// vue-eslint-parser options
720
parser?: boolean | string
@@ -37,6 +50,8 @@ export interface ParserOptions {
3750

3851
// others
3952
// [key: string]: any
53+
54+
templateTokenizer?: TemplateTokenizerConstructor
4055
}
4156

4257
export function isSFCFile(parserOptions: ParserOptions) {

src/html/parser.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import type {
1515
VDocumentFragment,
1616
VElement,
1717
VExpressionContainer,
18+
VLiteral,
1819
} from "../ast"
1920
import { NS, ParseError } from "../ast"
2021
import { debug } from "../common/debug"
@@ -641,6 +642,38 @@ export class Parser {
641642
debug("[html] Text %j", token)
642643

643644
const parent = this.currentNode
645+
if (parent.type === "VElement" && parent.name === "template") {
646+
const langAttribute = parent.startTag.attributes.find(
647+
(a) => a.key.name === "lang",
648+
)
649+
const lang = (langAttribute?.value as VLiteral).value
650+
if (
651+
lang &&
652+
lang !== "html" &&
653+
this.baseParserOptions.templateTokenizer[lang]
654+
) {
655+
// eslint-disable-next-line @typescript-eslint/no-require-imports
656+
const TemplateTokenizer = require(this.baseParserOptions
657+
.templateTokenizer[lang])
658+
const templateTokenizer = new TemplateTokenizer(
659+
token.value,
660+
this.text,
661+
{
662+
startingLine: token.loc.start.line,
663+
startingColumn: token.loc.start.column,
664+
},
665+
)
666+
667+
let templateToken: IntermediateToken | null = null
668+
while (
669+
(templateToken = templateTokenizer.nextToken()) != null
670+
) {
671+
;(this as any)[templateToken.type](templateToken)
672+
}
673+
// TODO integrate templateTokenizer.tokens/errors/comments
674+
return
675+
}
676+
}
644677
parent.children.push({
645678
type: "VText",
646679
range: token.range,

src/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ function isVueFile(code: string, options: ParserOptions): boolean {
4343
* @param parserOptions The parser options.
4444
* @returns The parsing result.
4545
*/
46+
// eslint-disable-next-line complexity
4647
export function parseForESLint(
4748
code: string,
4849
parserOptions: any,
@@ -97,13 +98,16 @@ export function parseForESLint(
9798
const scripts = rootAST.children.filter(isScriptElement)
9899
const template = rootAST.children.find(isTemplateElement)
99100
const templateLang = getLang(template) || "html"
101+
const hasTemplateTokenizer =
102+
parserOptions.templateTokenizer[templateLang]
100103
const concreteInfo: AST.HasConcreteInfo = {
101104
tokens: rootAST.tokens,
102105
comments: rootAST.comments,
103106
errors: rootAST.errors,
104107
}
105108
const templateBody =
106-
template != null && templateLang === "html"
109+
template != null &&
110+
(templateLang === "html" || hasTemplateTokenizer)
107111
? Object.assign(template, concreteInfo)
108112
: undefined
109113

0 commit comments

Comments
 (0)