wip: defineContext -> useOptions

This commit is contained in:
Evan You
2020-11-12 22:51:40 -05:00
parent 292a657861
commit 001f8ce993
5 changed files with 131 additions and 128 deletions

View File

@@ -28,7 +28,7 @@ import { genCssVarsCode, injectCssVarsCalls } from './genCssVars'
import { compileTemplate, SFCTemplateCompileOptions } from './compileTemplate'
import { BindingTypes } from 'packages/compiler-core/src/options'
const CTX_FN_NAME = 'defineContext'
const USE_OPTIONS = 'useOptions'
export interface SFCScriptCompileOptions {
/**
@@ -143,10 +143,10 @@ export function compileScript(
const refIdentifiers: Set<Identifier> = new Set()
const enableRefSugar = options.refSugar !== false
let defaultExport: Node | undefined
let hasContextCall = false
let setupContextExp: string | undefined
let setupContextArg: ObjectExpression | undefined
let setupContextType: TSTypeLiteral | undefined
let hasOptionsCall = false
let optionsExp: string | undefined
let optionsArg: ObjectExpression | undefined
let optionsType: TSTypeLiteral | undefined
let hasAwait = false
const s = new MagicString(source)
@@ -183,39 +183,39 @@ export function compileScript(
)
}
function processContextCall(node: Node): boolean {
function processUseOptions(node: Node): boolean {
if (
node.type === 'CallExpression' &&
node.callee.type === 'Identifier' &&
node.callee.name === CTX_FN_NAME
node.callee.name === USE_OPTIONS
) {
if (hasContextCall) {
error('duplicate defineContext() call', node)
if (hasOptionsCall) {
error(`duplicate ${USE_OPTIONS}() call`, node)
}
hasContextCall = true
hasOptionsCall = true
const optsArg = node.arguments[0]
if (optsArg) {
if (optsArg.type === 'ObjectExpression') {
setupContextArg = optsArg
optionsArg = optsArg
} else {
error(`${CTX_FN_NAME}() argument must be an object literal.`, optsArg)
error(`${USE_OPTIONS}() argument must be an object literal.`, optsArg)
}
}
// context call has type parameters - infer runtime types from it
if (node.typeParameters) {
if (setupContextArg) {
if (optionsArg) {
error(
`${CTX_FN_NAME}() cannot accept both type and non-type arguments ` +
`${USE_OPTIONS}() cannot accept both type and non-type arguments ` +
`at the same time. Use one or the other.`,
node
)
}
const typeArg = node.typeParameters.params[0]
if (typeArg.type === 'TSTypeLiteral') {
setupContextType = typeArg
optionsType = typeArg
} else {
error(
`type argument passed to ${CTX_FN_NAME}() must be a literal type.`,
`type argument passed to ${USE_OPTIONS}() must be a literal type.`,
typeArg
)
}
@@ -513,7 +513,7 @@ export function compileScript(
specifier.imported.name
const source = node.source.value
const existing = userImports[local]
if (source === 'vue' && imported === CTX_FN_NAME) {
if (source === 'vue' && imported === USE_OPTIONS) {
removed++
s.remove(
prev ? prev.end! + startOffset : specifier.start! + startOffset,
@@ -545,18 +545,15 @@ export function compileScript(
if (
node.type === 'ExpressionStatement' &&
processContextCall(node.expression)
processUseOptions(node.expression)
) {
s.remove(node.start! + startOffset, node.end! + startOffset)
}
if (node.type === 'VariableDeclaration' && !node.declare) {
for (const decl of node.declarations) {
if (decl.init && processContextCall(decl.init)) {
setupContextExp = scriptSetup.content.slice(
decl.id.start!,
decl.id.end!
)
if (decl.init && processUseOptions(decl.init)) {
optionsExp = scriptSetup.content.slice(decl.id.start!, decl.id.end!)
if (node.declarations.length === 1) {
s.remove(node.start! + startOffset, node.end! + startOffset)
} else {
@@ -649,8 +646,8 @@ export function compileScript(
}
// 5. extract runtime props/emits code from setup context type
if (setupContextType) {
for (const m of setupContextType.members) {
if (optionsType) {
for (const m of optionsType.members) {
if (m.type === 'TSPropertySignature' && m.key.type === 'Identifier') {
const typeNode = m.typeAnnotation!.typeAnnotation
const typeString = scriptSetup.content.slice(
@@ -688,13 +685,13 @@ export function compileScript(
}
}
// 5. check useSetupContext args to make sure it doesn't reference setup scope
// 5. check useOptions args to make sure it doesn't reference setup scope
// variables
if (setupContextArg) {
walkIdentifiers(setupContextArg, id => {
if (optionsArg) {
walkIdentifiers(optionsArg, id => {
if (setupBindings[id.name]) {
error(
`\`${CTX_FN_NAME}()\` in <script setup> cannot reference locally ` +
`\`${USE_OPTIONS}()\` in <script setup> cannot reference locally ` +
`declared variables because it will be hoisted outside of the ` +
`setup() function. If your component options requires initialization ` +
`in the module scope, use a separate normal <script> to export ` +
@@ -725,8 +722,8 @@ export function compileScript(
}
// 7. finalize setup argument signature.
let args = setupContextExp ? `__props, ${setupContextExp}` : ``
if (setupContextExp && setupContextType) {
let args = optionsExp ? `__props, ${optionsExp}` : ``
if (optionsExp && optionsType) {
if (slotsType === 'Slots') {
helperImports.add('Slots')
}
@@ -761,13 +758,13 @@ export function compileScript(
if (scriptAst) {
Object.assign(bindingMetadata, analyzeScriptBindings(scriptAst))
}
if (setupContextType) {
if (optionsType) {
for (const key in typeDeclaredProps) {
bindingMetadata[key] = BindingTypes.PROPS
}
}
if (setupContextArg) {
Object.assign(bindingMetadata, analyzeBindingsFromOptions(setupContextArg))
if (optionsArg) {
Object.assign(bindingMetadata, analyzeBindingsFromOptions(optionsArg))
}
for (const [key, { source }] of Object.entries(userImports)) {
bindingMetadata[key] = source.endsWith('.vue')
@@ -818,11 +815,11 @@ export function compileScript(
// 12. finalize default export
let runtimeOptions = ``
if (setupContextArg) {
if (optionsArg) {
runtimeOptions = `\n ${scriptSetup.content
.slice(setupContextArg.start! + 1, setupContextArg.end! - 1)
.slice(optionsArg.start! + 1, optionsArg.end! - 1)
.trim()},`
} else if (setupContextType) {
} else if (optionsType) {
runtimeOptions =
genRuntimeProps(typeDeclaredProps) + genRuntimeEmits(typeDeclaredEmits)
}
@@ -896,18 +893,18 @@ function walkDeclaration(
const isConst = node.kind === 'const'
// export const foo = ...
for (const { id, init } of node.declarations) {
const isContextCall = !!(
const isUseOptionsCall = !!(
isConst &&
init &&
init.type === 'CallExpression' &&
init.callee.type === 'Identifier' &&
init.callee.name === CTX_FN_NAME
init.callee.name === USE_OPTIONS
)
if (id.type === 'Identifier') {
bindings[id.name] =
// if a declaration is a const literal, we can mark it so that
// the generated render fn code doesn't need to unref() it
isContextCall ||
isUseOptionsCall ||
(isConst &&
init!.type !== 'Identifier' && // const a = b
init!.type !== 'CallExpression' && // const a = ref()
@@ -915,9 +912,9 @@ function walkDeclaration(
? BindingTypes.CONST
: BindingTypes.SETUP
} else if (id.type === 'ObjectPattern') {
walkObjectPattern(id, bindings, isConst, isContextCall)
walkObjectPattern(id, bindings, isConst, isUseOptionsCall)
} else if (id.type === 'ArrayPattern') {
walkArrayPattern(id, bindings, isConst, isContextCall)
walkArrayPattern(id, bindings, isConst, isUseOptionsCall)
}
}
} else if (
@@ -934,7 +931,7 @@ function walkObjectPattern(
node: ObjectPattern,
bindings: Record<string, BindingTypes>,
isConst: boolean,
isContextCall = false
isUseOptionsCall = false
) {
for (const p of node.properties) {
if (p.type === 'ObjectProperty') {
@@ -942,11 +939,11 @@ function walkObjectPattern(
if (p.key.type === 'Identifier') {
if (p.key === p.value) {
// const { x } = ...
bindings[p.key.name] = isContextCall
bindings[p.key.name] = isUseOptionsCall
? BindingTypes.CONST
: BindingTypes.SETUP
} else {
walkPattern(p.value, bindings, isConst, isContextCall)
walkPattern(p.value, bindings, isConst, isUseOptionsCall)
}
}
} else {
@@ -963,10 +960,10 @@ function walkArrayPattern(
node: ArrayPattern,
bindings: Record<string, BindingTypes>,
isConst: boolean,
isContextCall = false
isUseOptionsCall = false
) {
for (const e of node.elements) {
e && walkPattern(e, bindings, isConst, isContextCall)
e && walkPattern(e, bindings, isConst, isUseOptionsCall)
}
}
@@ -974,10 +971,10 @@ function walkPattern(
node: Node,
bindings: Record<string, BindingTypes>,
isConst: boolean,
isContextCall = false
isUseOptionsCall = false
) {
if (node.type === 'Identifier') {
bindings[node.name] = isContextCall
bindings[node.name] = isUseOptionsCall
? BindingTypes.CONST
: BindingTypes.SETUP
} else if (node.type === 'RestElement') {
@@ -991,7 +988,7 @@ function walkPattern(
walkArrayPattern(node, bindings, isConst)
} else if (node.type === 'AssignmentPattern') {
if (node.left.type === 'Identifier') {
bindings[node.left.name] = isContextCall
bindings[node.left.name] = isUseOptionsCall
? BindingTypes.CONST
: BindingTypes.SETUP
} else {