@@ -23,6 +23,8 @@ import {
2323 isTemplateElement ,
2424} from "./common/ast-utils"
2525import { parseStyleElements } from "./style"
26+ import { analyzeScope } from "./script/scope-analyzer"
27+ import { analyzeScriptSetupScope } from "./script-setup/scope-analyzer"
2628
2729const STARTS_WITH_LT = / ^ \s * < / u
2830
@@ -61,101 +63,11 @@ export function parseForESLint(
6163 let document : AST . VDocumentFragment | null
6264 let locationCalculator : LocationCalculatorForHtml | null
6365 if ( ! isVueFile ( code , options ) ) {
64- result = parseScript ( code , {
65- ...options ,
66- ecmaVersion : options . ecmaVersion || DEFAULT_ECMA_VERSION ,
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 ( / ^ [ j t ] s x $ / u. test ( ext ) ) {
76- return [ ext , ext . slice ( 0 , - 1 ) ]
77- }
78-
79- return ext
80- } ) ,
81- } )
66+ result = parseAsScript ( code , options )
8267 document = null
8368 locationCalculator = null
8469 } else {
85- const optionsForTemplate = {
86- ...options ,
87- ecmaVersion : options . ecmaVersion || DEFAULT_ECMA_VERSION ,
88- }
89- const skipParsingScript = options . parser === false
90- const tokenizer = new HTMLTokenizer ( code , optionsForTemplate )
91- const rootAST = new HTMLParser ( tokenizer , optionsForTemplate ) . parse ( )
92-
93- locationCalculator = new LocationCalculatorForHtml (
94- tokenizer . gaps ,
95- tokenizer . lineTerminators ,
96- )
97- const scripts = rootAST . children . filter ( isScriptElement )
98- const template = rootAST . children . find ( isTemplateElement )
99- const templateLang = getLang ( template ) || "html"
100- const concreteInfo : AST . HasConcreteInfo = {
101- tokens : rootAST . tokens ,
102- comments : rootAST . comments ,
103- errors : rootAST . errors ,
104- }
105- const templateBody =
106- template != null && templateLang === "html"
107- ? Object . assign ( template , concreteInfo )
108- : undefined
109-
110- const scriptParser = getScriptParser ( options . parser , ( ) =>
111- getParserLangFromSFC ( rootAST ) ,
112- )
113- let scriptSetup : VElement | undefined
114- if ( skipParsingScript || ! scripts . length ) {
115- result = parseScript ( "" , {
116- ...options ,
117- ecmaVersion : options . ecmaVersion || DEFAULT_ECMA_VERSION ,
118- parser : scriptParser ,
119- } )
120- } else if (
121- scripts . length === 2 &&
122- ( scriptSetup = scripts . find ( isScriptSetupElement ) )
123- ) {
124- result = parseScriptSetupElements (
125- scriptSetup ,
126- scripts . find ( ( e ) => e !== scriptSetup ) ! ,
127- code ,
128- new LinesAndColumns ( tokenizer . lineTerminators ) ,
129- {
130- ...options ,
131- parser : scriptParser ,
132- } ,
133- )
134- } else {
135- result = parseScriptElement (
136- scripts [ 0 ] ,
137- code ,
138- new LinesAndColumns ( tokenizer . lineTerminators ) ,
139- {
140- ...options ,
141- parser : scriptParser ,
142- } ,
143- )
144- }
145-
146- if ( options . vueFeatures ?. styleCSSVariableInjection ?? true ) {
147- const styles = rootAST . children . filter ( isStyleElement )
148- parseStyleElements ( styles , locationCalculator , {
149- ...options ,
150- parser : getScriptParser ( options . parser , function * ( ) {
151- yield "<template>"
152- yield getParserLangFromSFC ( rootAST )
153- } ) ,
154- } )
155- }
156-
157- result . ast . templateBody = templateBody
158- document = rootAST
70+ ; ( { result, document, locationCalculator } = parseAsSFC ( code , options ) )
15971 }
16072
16173 result . services = Object . assign (
@@ -179,3 +91,119 @@ export function parse(code: string, options: any): AST.ESLintProgram {
17991}
18092
18193export { AST }
94+
95+ function parseAsSFC ( code : string , options : ParserOptions ) {
96+ const optionsForTemplate = {
97+ ...options ,
98+ ecmaVersion : options . ecmaVersion || DEFAULT_ECMA_VERSION ,
99+ }
100+ const skipParsingScript = options . parser === false
101+ const tokenizer = new HTMLTokenizer ( code , optionsForTemplate )
102+ const rootAST = new HTMLParser ( tokenizer , optionsForTemplate ) . parse ( )
103+
104+ const locationCalculator = new LocationCalculatorForHtml (
105+ tokenizer . gaps ,
106+ tokenizer . lineTerminators ,
107+ )
108+ const scripts = rootAST . children . filter ( isScriptElement )
109+ const template = rootAST . children . find ( isTemplateElement )
110+ const templateLang = getLang ( template ) || "html"
111+ const concreteInfo : AST . HasConcreteInfo = {
112+ tokens : rootAST . tokens ,
113+ comments : rootAST . comments ,
114+ errors : rootAST . errors ,
115+ }
116+ const templateBody =
117+ template != null && templateLang === "html"
118+ ? Object . assign ( template , concreteInfo )
119+ : undefined
120+
121+ const scriptParser = getScriptParser ( options . parser , ( ) =>
122+ getParserLangFromSFC ( rootAST ) ,
123+ )
124+ let result : AST . ESLintExtendedProgram
125+ let scriptSetup : VElement | undefined
126+ if ( skipParsingScript || ! scripts . length ) {
127+ result = parseScript ( "" , {
128+ ...options ,
129+ ecmaVersion : options . ecmaVersion || DEFAULT_ECMA_VERSION ,
130+ parser : scriptParser ,
131+ } )
132+ } else if (
133+ scripts . length === 2 &&
134+ ( scriptSetup = scripts . find ( isScriptSetupElement ) )
135+ ) {
136+ result = parseScriptSetupElements (
137+ scriptSetup ,
138+ scripts . find ( ( e ) => e !== scriptSetup ) ! ,
139+ code ,
140+ new LinesAndColumns ( tokenizer . lineTerminators ) ,
141+ {
142+ ...options ,
143+ parser : scriptParser ,
144+ } ,
145+ )
146+ } else {
147+ result = parseScriptElement (
148+ scripts [ 0 ] ,
149+ code ,
150+ new LinesAndColumns ( tokenizer . lineTerminators ) ,
151+ {
152+ ...options ,
153+ parser : scriptParser ,
154+ } ,
155+ )
156+ }
157+
158+ if ( options . vueFeatures ?. styleCSSVariableInjection ?? true ) {
159+ const styles = rootAST . children . filter ( isStyleElement )
160+ parseStyleElements ( styles , locationCalculator , {
161+ ...options ,
162+ parser : getScriptParser ( options . parser , function * ( ) {
163+ yield "<template>"
164+ yield getParserLangFromSFC ( rootAST )
165+ } ) ,
166+ } )
167+ }
168+ result . ast . templateBody = templateBody
169+
170+ if ( options . eslintScopeManager ) {
171+ if ( scripts . some ( isScriptSetupElement ) ) {
172+ if ( ! result . scopeManager ) {
173+ result . scopeManager = analyzeScope ( result . ast , options )
174+ }
175+ analyzeScriptSetupScope (
176+ result . scopeManager ,
177+ templateBody ,
178+ rootAST ,
179+ options ,
180+ )
181+ }
182+ }
183+
184+ return {
185+ result,
186+ locationCalculator,
187+ document : rootAST ,
188+ }
189+ }
190+
191+ function parseAsScript ( code : string , options : ParserOptions ) {
192+ return parseScript ( code , {
193+ ...options ,
194+ ecmaVersion : options . ecmaVersion || DEFAULT_ECMA_VERSION ,
195+ parser : getScriptParser ( options . parser , ( ) => {
196+ const ext = (
197+ path . extname ( options . filePath || "unknown.js" ) . toLowerCase ( ) ||
198+ ""
199+ )
200+ // remove dot
201+ . slice ( 1 )
202+ if ( / ^ [ j t ] s x $ / u. test ( ext ) ) {
203+ return [ ext , ext . slice ( 0 , - 1 ) ]
204+ }
205+
206+ return ext
207+ } ) ,
208+ } )
209+ }
0 commit comments