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…
Reference in New Issue
Block a user