@@ -23,6 +23,8 @@ import {
23
23
isTemplateElement ,
24
24
} from "./common/ast-utils"
25
25
import { parseStyleElements } from "./style"
26
+ import { analyzeScope } from "./script/scope-analyzer"
27
+ import { analyzeScriptSetupScope } from "./script-setup/scope-analyzer"
26
28
27
29
const STARTS_WITH_LT = / ^ \s * < / u
28
30
@@ -61,101 +63,11 @@ export function parseForESLint(
61
63
let document : AST . VDocumentFragment | null
62
64
let locationCalculator : LocationCalculatorForHtml | null
63
65
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 )
82
67
document = null
83
68
locationCalculator = null
84
69
} 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 ) )
159
71
}
160
72
161
73
result . services = Object . assign (
@@ -179,3 +91,119 @@ export function parse(code: string, options: any): AST.ESLintProgram {
179
91
}
180
92
181
93
export { 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