refactor(compiler-sfc): remove parseOnly mode
This commit is contained in:
		
							parent
							
								
									db8dc753c0
								
							
						
					
					
						commit
						0c2ea1c134
					
				| @ -1,87 +0,0 @@ | |||||||
| import { TextRange } from '../src/parse' |  | ||||||
| import { compileSFCScript } from './utils' |  | ||||||
| 
 |  | ||||||
| describe('compileScript parseOnly mode', () => { |  | ||||||
|   function compile(src: string) { |  | ||||||
|     return compileSFCScript(src, { parseOnly: true }) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   function getRange(src: string, range: TextRange) { |  | ||||||
|     return src.slice(range.start, range.end) |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   test('bindings', () => { |  | ||||||
|     const scriptSrc = ` |  | ||||||
|     import { foo } from './x' |  | ||||||
|     ` |  | ||||||
|     const scriptSetupSrc = ` |  | ||||||
|     import { bar } from './x' |  | ||||||
| 
 |  | ||||||
|     const a = 123 |  | ||||||
|     function b() {} |  | ||||||
|     class c {} |  | ||||||
|     ` |  | ||||||
|     const src = ` |  | ||||||
|     <script>${scriptSrc}</script> |  | ||||||
|     <script setup>${scriptSetupSrc}</script> |  | ||||||
|     ` |  | ||||||
|     const { ranges } = compile(src) |  | ||||||
| 
 |  | ||||||
|     expect(getRange(scriptSrc, ranges!.scriptBindings[0])).toBe('foo') |  | ||||||
|     expect( |  | ||||||
|       ranges!.scriptSetupBindings.map(r => getRange(scriptSetupSrc, r)) |  | ||||||
|     ).toMatchObject(['bar', 'a', 'b', 'c']) |  | ||||||
|   }) |  | ||||||
| 
 |  | ||||||
|   test('defineProps', () => { |  | ||||||
|     const src = ` |  | ||||||
|     defineProps({ foo: String }) |  | ||||||
|     ` |  | ||||||
|     const { ranges } = compile(`<script setup>${src}</script>`) |  | ||||||
|     expect(getRange(src, ranges!.propsRuntimeArg!)).toBe(`{ foo: String }`) |  | ||||||
|   }) |  | ||||||
| 
 |  | ||||||
|   test('defineProps (type)', () => { |  | ||||||
|     const src = ` |  | ||||||
|     interface Props { x?: number } |  | ||||||
|     defineProps<Props>() |  | ||||||
|     ` |  | ||||||
|     const { ranges } = compile(`<script setup lang="ts">${src}</script>`) |  | ||||||
|     expect(getRange(src, ranges!.propsTypeArg!)).toBe(`Props`) |  | ||||||
|   }) |  | ||||||
| 
 |  | ||||||
|   test('withDefaults', () => { |  | ||||||
|     const src = ` |  | ||||||
|     interface Props { x?: number } |  | ||||||
|     withDefaults(defineProps<Props>(), { x: 1 }) |  | ||||||
|     ` |  | ||||||
|     const { ranges } = compile(`<script setup lang="ts">${src}</script>`) |  | ||||||
|     expect(getRange(src, ranges!.withDefaultsArg!)).toBe(`{ x: 1 }`) |  | ||||||
|   }) |  | ||||||
| 
 |  | ||||||
|   test('defineEmits', () => { |  | ||||||
|     const src = ` |  | ||||||
|     defineEmits(['foo']) |  | ||||||
|     ` |  | ||||||
|     const { ranges } = compile(`<script setup>${src}</script>`) |  | ||||||
|     expect(getRange(src, ranges!.emitsRuntimeArg!)).toBe(`['foo']`) |  | ||||||
|   }) |  | ||||||
| 
 |  | ||||||
|   test('defineEmits (type)', () => { |  | ||||||
|     const src = ` |  | ||||||
|     defineEmits<{ (e: 'x'): void }>() |  | ||||||
|     ` |  | ||||||
|     const { ranges } = compile(`<script setup lang="ts">${src}</script>`) |  | ||||||
|     expect(getRange(src, ranges!.emitsTypeArg!)).toBe(`{ (e: 'x'): void }`) |  | ||||||
|   }) |  | ||||||
| 
 |  | ||||||
|   test('no script setup block', () => { |  | ||||||
|     const src = `import { x } from './x'` |  | ||||||
|     const { ranges } = compile(`<script>${src}</script>`) |  | ||||||
|     expect(getRange(src, ranges!.scriptBindings[0])).toBe(`x`) |  | ||||||
|   }) |  | ||||||
| 
 |  | ||||||
|   test('no script block', () => { |  | ||||||
|     expect(() => compile(`<style>hello</style>`)).not.toThrow() |  | ||||||
|   }) |  | ||||||
| }) |  | ||||||
| @ -3,7 +3,6 @@ import { | |||||||
|   BindingMetadata, |   BindingMetadata, | ||||||
|   BindingTypes, |   BindingTypes, | ||||||
|   createRoot, |   createRoot, | ||||||
|   locStub, |  | ||||||
|   NodeTypes, |   NodeTypes, | ||||||
|   transform, |   transform, | ||||||
|   parserOptions, |   parserOptions, | ||||||
| @ -12,12 +11,7 @@ import { | |||||||
|   isFunctionType, |   isFunctionType, | ||||||
|   walkIdentifiers |   walkIdentifiers | ||||||
| } from '@vue/compiler-dom' | } from '@vue/compiler-dom' | ||||||
| import { | import { SFCDescriptor, SFCScriptBlock } from './parse' | ||||||
|   ScriptSetupTextRanges, |  | ||||||
|   SFCDescriptor, |  | ||||||
|   SFCScriptBlock, |  | ||||||
|   TextRange |  | ||||||
| } from './parse' |  | ||||||
| import { parse as _parse, ParserOptions, ParserPlugin } from '@babel/parser' | import { parse as _parse, ParserOptions, ParserPlugin } from '@babel/parser' | ||||||
| import { | import { | ||||||
|   babelParserDefaultPlugins, |   babelParserDefaultPlugins, | ||||||
| @ -103,28 +97,16 @@ export interface SFCScriptCompileOptions { | |||||||
|    * options passed to `compiler-dom`. |    * options passed to `compiler-dom`. | ||||||
|    */ |    */ | ||||||
|   templateOptions?: Partial<SFCTemplateCompileOptions> |   templateOptions?: Partial<SFCTemplateCompileOptions> | ||||||
|   /** |  | ||||||
|    * Skip codegen and only return AST / binding / text range information. |  | ||||||
|    * Also makes the call error-tolerant. |  | ||||||
|    * Used for IDE support. |  | ||||||
|    */ |  | ||||||
|   parseOnly?: boolean |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| interface ImportBinding { | interface ImportBinding { | ||||||
|   isType: boolean |   isType: boolean | ||||||
|   imported: string |   imported: string | ||||||
|   source: string |   source: string | ||||||
|   rangeNode: Node |  | ||||||
|   isFromSetup: boolean |   isFromSetup: boolean | ||||||
|   isUsedInTemplate: boolean |   isUsedInTemplate: boolean | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| interface VariableBinding { |  | ||||||
|   type: BindingTypes |  | ||||||
|   rangeNode: Node |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /** | /** | ||||||
|  * Compile `<script setup>` |  * Compile `<script setup>` | ||||||
|  * It requires the whole SFC descriptor because we need to handle and merge |  * It requires the whole SFC descriptor because we need to handle and merge | ||||||
| @ -138,18 +120,6 @@ export function compileScript( | |||||||
|   // feature flags
 |   // feature flags
 | ||||||
|   const enableRefSugar = !!options.refSugar |   const enableRefSugar = !!options.refSugar | ||||||
|   let refBindings: string[] | undefined |   let refBindings: string[] | undefined | ||||||
|   const parseOnly = !!options.parseOnly |  | ||||||
| 
 |  | ||||||
|   if (parseOnly && !scriptSetup) { |  | ||||||
|     // in parse-only mode, construct a fake script setup so we still perform
 |  | ||||||
|     // the full parse logic.
 |  | ||||||
|     scriptSetup = { |  | ||||||
|       type: 'script', |  | ||||||
|       content: '', |  | ||||||
|       attrs: {}, |  | ||||||
|       loc: locStub |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   // for backwards compat
 |   // for backwards compat
 | ||||||
|   if (!options) { |   if (!options) { | ||||||
| @ -190,8 +160,7 @@ export function compileScript( | |||||||
|     try { |     try { | ||||||
|       const scriptAst = _parse(script.content, { |       const scriptAst = _parse(script.content, { | ||||||
|         plugins, |         plugins, | ||||||
|         sourceType: 'module', |         sourceType: 'module' | ||||||
|         errorRecovery: parseOnly |  | ||||||
|       }).program.body |       }).program.body | ||||||
|       const bindings = analyzeScriptBindings(scriptAst) |       const bindings = analyzeScriptBindings(scriptAst) | ||||||
|       let content = script.content |       let content = script.content | ||||||
| @ -232,18 +201,11 @@ export function compileScript( | |||||||
| 
 | 
 | ||||||
|   // metadata that needs to be returned
 |   // metadata that needs to be returned
 | ||||||
|   const bindingMetadata: BindingMetadata = {} |   const bindingMetadata: BindingMetadata = {} | ||||||
|   const ranges: ScriptSetupTextRanges | undefined = parseOnly |  | ||||||
|     ? { |  | ||||||
|         scriptBindings: [], |  | ||||||
|         scriptSetupBindings: [] |  | ||||||
|       } |  | ||||||
|     : undefined |  | ||||||
| 
 |  | ||||||
|   const defaultTempVar = `__default__` |   const defaultTempVar = `__default__` | ||||||
|   const helperImports: Set<string> = new Set() |   const helperImports: Set<string> = new Set() | ||||||
|   const userImports: Record<string, ImportBinding> = Object.create(null) |   const userImports: Record<string, ImportBinding> = Object.create(null) | ||||||
|   const userImportAlias: Record<string, string> = Object.create(null) |   const userImportAlias: Record<string, string> = Object.create(null) | ||||||
|   const setupBindings: Record<string, VariableBinding> = Object.create(null) |   const setupBindings: Record<string, BindingTypes> = Object.create(null) | ||||||
| 
 | 
 | ||||||
|   let defaultExport: Node | undefined |   let defaultExport: Node | undefined | ||||||
|   let hasDefinePropsCall = false |   let hasDefinePropsCall = false | ||||||
| @ -288,7 +250,6 @@ export function compileScript( | |||||||
|     offset: number |     offset: number | ||||||
|   ): Program { |   ): Program { | ||||||
|     try { |     try { | ||||||
|       options.errorRecovery = parseOnly |  | ||||||
|       return _parse(input, options).program |       return _parse(input, options).program | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       e.message = `[@vue/compiler-sfc] ${e.message}\n\n${ |       e.message = `[@vue/compiler-sfc] ${e.message}\n\n${ | ||||||
| @ -317,8 +278,7 @@ export function compileScript( | |||||||
|     local: string, |     local: string, | ||||||
|     imported: string | false, |     imported: string | false, | ||||||
|     isType: boolean, |     isType: boolean, | ||||||
|     isFromSetup: boolean, |     isFromSetup: boolean | ||||||
|     rangeNode: Node |  | ||||||
|   ) { |   ) { | ||||||
|     if (source === 'vue' && imported) { |     if (source === 'vue' && imported) { | ||||||
|       userImportAlias[imported] = local |       userImportAlias[imported] = local | ||||||
| @ -337,7 +297,6 @@ export function compileScript( | |||||||
|       isType, |       isType, | ||||||
|       imported: imported || 'default', |       imported: imported || 'default', | ||||||
|       source, |       source, | ||||||
|       rangeNode, |  | ||||||
|       isFromSetup, |       isFromSetup, | ||||||
|       isUsedInTemplate |       isUsedInTemplate | ||||||
|     } |     } | ||||||
| @ -609,8 +568,7 @@ export function compileScript( | |||||||
|             specifier.local.name, |             specifier.local.name, | ||||||
|             imported, |             imported, | ||||||
|             node.importKind === 'type', |             node.importKind === 'type', | ||||||
|             false, |             false | ||||||
|             specifier.local |  | ||||||
|           ) |           ) | ||||||
|         } |         } | ||||||
|       } else if (node.type === 'ExportDefaultDeclaration') { |       } else if (node.type === 'ExportDefaultDeclaration') { | ||||||
| @ -705,8 +663,8 @@ export function compileScript( | |||||||
|     ) { |     ) { | ||||||
|       error( |       error( | ||||||
|         `ref sugar using the label syntax was an experimental proposal and ` + |         `ref sugar using the label syntax was an experimental proposal and ` + | ||||||
|           `has been dropped based on community feedback.`, |           `has been dropped based on community feedback. Please check out ` + | ||||||
|         // TODO + ` Please check out the adjusted proposal at ...`,
 |           `the new proposal at https://github.com/vuejs/rfcs/discussions/369`, | ||||||
|         node |         node | ||||||
|       ) |       ) | ||||||
|     } |     } | ||||||
| @ -764,8 +722,7 @@ export function compileScript( | |||||||
|             local, |             local, | ||||||
|             imported, |             imported, | ||||||
|             node.importKind === 'type', |             node.importKind === 'type', | ||||||
|             true, |             true | ||||||
|             specifier.local |  | ||||||
|           ) |           ) | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
| @ -897,44 +854,6 @@ export function compileScript( | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // in parse only mode, we should have collected all the information we need,
 |  | ||||||
|   // return early.
 |  | ||||||
|   if (parseOnly) { |  | ||||||
|     for (const key in userImports) { |  | ||||||
|       const { rangeNode, isFromSetup } = userImports[key] |  | ||||||
|       const bindings = isFromSetup |  | ||||||
|         ? ranges!.scriptSetupBindings |  | ||||||
|         : ranges!.scriptBindings |  | ||||||
|       bindings.push(toTextRange(rangeNode)) |  | ||||||
|     } |  | ||||||
|     for (const key in setupBindings) { |  | ||||||
|       ranges!.scriptSetupBindings.push( |  | ||||||
|         toTextRange(setupBindings[key].rangeNode) |  | ||||||
|       ) |  | ||||||
|     } |  | ||||||
|     if (propsRuntimeDecl) { |  | ||||||
|       ranges!.propsRuntimeArg = toTextRange(propsRuntimeDecl) |  | ||||||
|     } |  | ||||||
|     if (propsTypeDeclRaw) { |  | ||||||
|       ranges!.propsTypeArg = toTextRange(propsTypeDeclRaw) |  | ||||||
|     } |  | ||||||
|     if (emitsRuntimeDecl) { |  | ||||||
|       ranges!.emitsRuntimeArg = toTextRange(emitsRuntimeDecl) |  | ||||||
|     } |  | ||||||
|     if (emitsTypeDeclRaw) { |  | ||||||
|       ranges!.emitsTypeArg = toTextRange(emitsTypeDeclRaw) |  | ||||||
|     } |  | ||||||
|     if (propsRuntimeDefaults) { |  | ||||||
|       ranges!.withDefaultsArg = toTextRange(propsRuntimeDefaults) |  | ||||||
|     } |  | ||||||
|     return { |  | ||||||
|       ...scriptSetup, |  | ||||||
|       ranges, |  | ||||||
|       scriptAst: scriptAst?.body, |  | ||||||
|       scriptSetupAst: scriptSetupAst?.body |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   // 3. Apply ref sugar transform
 |   // 3. Apply ref sugar transform
 | ||||||
|   if (enableRefSugar) { |   if (enableRefSugar) { | ||||||
|     warnExperimental( |     warnExperimental( | ||||||
| @ -1007,7 +926,7 @@ export function compileScript( | |||||||
|         : BindingTypes.SETUP_MAYBE_REF |         : BindingTypes.SETUP_MAYBE_REF | ||||||
|   } |   } | ||||||
|   for (const key in setupBindings) { |   for (const key in setupBindings) { | ||||||
|     bindingMetadata[key] = setupBindings[key].type |     bindingMetadata[key] = setupBindings[key] | ||||||
|   } |   } | ||||||
|   // known ref bindings
 |   // known ref bindings
 | ||||||
|   if (refBindings) { |   if (refBindings) { | ||||||
| @ -1240,19 +1159,16 @@ export function compileScript( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function registerBinding( | function registerBinding( | ||||||
|   bindings: Record<string, VariableBinding>, |   bindings: Record<string, BindingTypes>, | ||||||
|   node: Identifier, |   node: Identifier, | ||||||
|   type: BindingTypes |   type: BindingTypes | ||||||
| ) { | ) { | ||||||
|   bindings[node.name] = { |   bindings[node.name] = type | ||||||
|     type, |  | ||||||
|     rangeNode: node |  | ||||||
|   } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function walkDeclaration( | function walkDeclaration( | ||||||
|   node: Declaration, |   node: Declaration, | ||||||
|   bindings: Record<string, VariableBinding>, |   bindings: Record<string, BindingTypes>, | ||||||
|   userImportAlias: Record<string, string> |   userImportAlias: Record<string, string> | ||||||
| ) { | ) { | ||||||
|   if (node.type === 'VariableDeclaration') { |   if (node.type === 'VariableDeclaration') { | ||||||
| @ -1301,16 +1217,13 @@ function walkDeclaration( | |||||||
|   ) { |   ) { | ||||||
|     // export function foo() {} / export class Foo {}
 |     // export function foo() {} / export class Foo {}
 | ||||||
|     // export declarations must be named.
 |     // export declarations must be named.
 | ||||||
|     bindings[node.id!.name] = { |     bindings[node.id!.name] = BindingTypes.SETUP_CONST | ||||||
|       type: BindingTypes.SETUP_CONST, |  | ||||||
|       rangeNode: node.id! |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function walkObjectPattern( | function walkObjectPattern( | ||||||
|   node: ObjectPattern, |   node: ObjectPattern, | ||||||
|   bindings: Record<string, VariableBinding>, |   bindings: Record<string, BindingTypes>, | ||||||
|   isConst: boolean, |   isConst: boolean, | ||||||
|   isDefineCall = false |   isDefineCall = false | ||||||
| ) { | ) { | ||||||
| @ -1341,7 +1254,7 @@ function walkObjectPattern( | |||||||
| 
 | 
 | ||||||
| function walkArrayPattern( | function walkArrayPattern( | ||||||
|   node: ArrayPattern, |   node: ArrayPattern, | ||||||
|   bindings: Record<string, VariableBinding>, |   bindings: Record<string, BindingTypes>, | ||||||
|   isConst: boolean, |   isConst: boolean, | ||||||
|   isDefineCall = false |   isDefineCall = false | ||||||
| ) { | ) { | ||||||
| @ -1352,7 +1265,7 @@ function walkArrayPattern( | |||||||
| 
 | 
 | ||||||
| function walkPattern( | function walkPattern( | ||||||
|   node: Node, |   node: Node, | ||||||
|   bindings: Record<string, VariableBinding>, |   bindings: Record<string, BindingTypes>, | ||||||
|   isConst: boolean, |   isConst: boolean, | ||||||
|   isDefineCall = false |   isDefineCall = false | ||||||
| ) { | ) { | ||||||
| @ -1745,13 +1658,6 @@ function getObjectOrArrayExpressionKeys(value: Node): string[] { | |||||||
|   return [] |   return [] | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| function toTextRange(node: Node): TextRange { |  | ||||||
|   return { |  | ||||||
|     start: node.start!, |  | ||||||
|     end: node.end! |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| const templateUsageCheckCache = createCache<string>() | const templateUsageCheckCache = createCache<string>() | ||||||
| 
 | 
 | ||||||
| function resolveTemplateUsageCheckString(sfc: SFCDescriptor) { | function resolveTemplateUsageCheckString(sfc: SFCDescriptor) { | ||||||
|  | |||||||
| @ -43,27 +43,7 @@ export interface SFCScriptBlock extends SFCBlock { | |||||||
|   bindings?: BindingMetadata |   bindings?: BindingMetadata | ||||||
|   scriptAst?: Statement[] |   scriptAst?: Statement[] | ||||||
|   scriptSetupAst?: Statement[] |   scriptSetupAst?: Statement[] | ||||||
|   ranges?: ScriptSetupTextRanges |  | ||||||
| } | } | ||||||
| 
 |  | ||||||
| /** |  | ||||||
|  * Text range data for IDE support |  | ||||||
|  */ |  | ||||||
| export interface ScriptSetupTextRanges { |  | ||||||
|   scriptBindings: TextRange[] |  | ||||||
|   scriptSetupBindings: TextRange[] |  | ||||||
|   propsTypeArg?: TextRange |  | ||||||
|   propsRuntimeArg?: TextRange |  | ||||||
|   emitsTypeArg?: TextRange |  | ||||||
|   emitsRuntimeArg?: TextRange |  | ||||||
|   withDefaultsArg?: TextRange |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export interface TextRange { |  | ||||||
|   start: number |  | ||||||
|   end: number |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export interface SFCStyleBlock extends SFCBlock { | export interface SFCStyleBlock extends SFCBlock { | ||||||
|   type: 'style' |   type: 'style' | ||||||
|   scoped?: boolean |   scoped?: boolean | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user