wip: useOptions -> defineOptions

This commit is contained in:
Evan You
2020-11-13 17:38:28 -05:00
parent 91d990d45a
commit 1ff5960971
6 changed files with 123 additions and 124 deletions

View File

@@ -27,7 +27,7 @@ import { RawSourceMap } from 'source-map'
import { genCssVarsCode, injectCssVarsCalls } from './genCssVars'
import { compileTemplate, SFCTemplateCompileOptions } from './compileTemplate'
const USE_OPTIONS = 'useOptions'
const DEFINE_OPTIONS = 'defineOptions'
export interface SFCScriptCompileOptions {
/**
@@ -147,7 +147,18 @@ export function compileScript(
let optionsArg: ObjectExpression | undefined
let optionsType: TSTypeLiteral | undefined
let hasAwait = false
// context types to generate
let propsType = `{}`
let emitType = `(e: string, ...args: any[]) => void`
let slotsType = `Slots`
let attrsType = `Record<string, any>`
// props/emits declared via types
const typeDeclaredProps: Record<string, PropTypeData> = {}
const typeDeclaredEmits: Set<string> = new Set()
// record declared types for runtime props type generation
const declaredTypes: Record<string, string[]> = {}
// magic-string state
const s = new MagicString(source)
const startOffset = scriptSetup.loc.start.offset
const endOffset = scriptSetup.loc.end.offset
@@ -182,14 +193,14 @@ export function compileScript(
)
}
function processUseOptions(node: Node): boolean {
function processDefineOptions(node: Node): boolean {
if (
node.type === 'CallExpression' &&
node.callee.type === 'Identifier' &&
node.callee.name === USE_OPTIONS
node.callee.name === DEFINE_OPTIONS
) {
if (hasOptionsCall) {
error(`duplicate ${USE_OPTIONS}() call`, node)
error(`duplicate ${DEFINE_OPTIONS}() call`, node)
}
hasOptionsCall = true
const optsArg = node.arguments[0]
@@ -197,14 +208,17 @@ export function compileScript(
if (optsArg.type === 'ObjectExpression') {
optionsArg = optsArg
} else {
error(`${USE_OPTIONS}() argument must be an object literal.`, optsArg)
error(
`${DEFINE_OPTIONS}() argument must be an object literal.`,
optsArg
)
}
}
// context call has type parameters - infer runtime types from it
if (node.typeParameters) {
if (optionsArg) {
error(
`${USE_OPTIONS}() cannot accept both type and non-type arguments ` +
`${DEFINE_OPTIONS}() cannot accept both type and non-type arguments ` +
`at the same time. Use one or the other.`,
node
)
@@ -214,7 +228,7 @@ export function compileScript(
optionsType = typeArg
} else {
error(
`type argument passed to ${USE_OPTIONS}() must be a literal type.`,
`type argument passed to ${DEFINE_OPTIONS}() must be a literal type.`,
typeArg
)
}
@@ -427,18 +441,7 @@ export function compileScript(
}
}
let propsType = `{}`
let emitType = `(e: string, ...args: any[]) => void`
let slotsType = `Slots`
let attrsType = `Record<string, any>`
// props/emits declared via types
const typeDeclaredProps: Record<string, PropTypeData> = {}
const typeDeclaredEmits: Set<string> = new Set()
// record declared types for runtime props type generation
const declaredTypes: Record<string, string[]> = {}
// 3. parse <script setup> and walk over top level statements
// 2. parse <script setup> and walk over top level statements
const scriptSetupAst = parse(
scriptSetup.content,
{
@@ -512,7 +515,7 @@ export function compileScript(
specifier.imported.name
const source = node.source.value
const existing = userImports[local]
if (source === 'vue' && imported === USE_OPTIONS) {
if (source === 'vue' && imported === DEFINE_OPTIONS) {
removed++
s.remove(
prev ? prev.end! + startOffset : specifier.start! + startOffset,
@@ -544,14 +547,14 @@ export function compileScript(
if (
node.type === 'ExpressionStatement' &&
processUseOptions(node.expression)
processDefineOptions(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 && processUseOptions(decl.init)) {
if (decl.init && processDefineOptions(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)
@@ -618,7 +621,7 @@ export function compileScript(
}
}
// 4. Do a full walk to rewrite identifiers referencing let exports with ref
// 3. Do a full walk to rewrite identifiers referencing let exports with ref
// value access
if (enableRefSugar && Object.keys(refBindings).length) {
for (const node of scriptSetupAst) {
@@ -644,7 +647,7 @@ export function compileScript(
}
}
// 5. extract runtime props/emits code from setup context type
// 4. extract runtime props/emits code from setup context type
if (optionsType) {
for (const m of optionsType.members) {
if (m.type === 'TSPropertySignature' && m.key.type === 'Identifier') {
@@ -690,7 +693,7 @@ export function compileScript(
walkIdentifiers(optionsArg, id => {
if (setupBindings[id.name]) {
error(
`\`${USE_OPTIONS}()\` in <script setup> cannot reference locally ` +
`\`${DEFINE_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 ` +
@@ -739,7 +742,7 @@ export function compileScript(
allBindings[key] = true
}
// 9. inject `useCssVars` calls
// 8. inject `useCssVars` calls
if (hasCssVars) {
helperImports.add(`useCssVars`)
for (const style of styles) {
@@ -753,7 +756,7 @@ export function compileScript(
}
}
// 10. analyze binding metadata
// 9. analyze binding metadata
if (scriptAst) {
Object.assign(bindingMetadata, analyzeScriptBindings(scriptAst))
}
@@ -774,7 +777,7 @@ export function compileScript(
bindingMetadata[key] = setupBindings[key]
}
// 11. generate return statement
// 10. generate return statement
let returned
if (options.inlineTemplate) {
if (sfc.template) {
@@ -812,7 +815,7 @@ export function compileScript(
}
s.appendRight(endOffset, `\nreturn ${returned}\n}\n\n`)
// 12. finalize default export
// 11. finalize default export
let runtimeOptions = ``
if (optionsArg) {
runtimeOptions = `\n ${scriptSetup.content
@@ -822,7 +825,6 @@ export function compileScript(
runtimeOptions =
genRuntimeProps(typeDeclaredProps) + genRuntimeEmits(typeDeclaredEmits)
}
if (isTS) {
// for TS, make sure the exported type is still valid type with
// correct props information
@@ -861,7 +863,7 @@ export function compileScript(
}
}
// 13. finalize Vue helper imports
// 12. finalize Vue helper imports
// TODO account for cases where user imports a helper with the same name
// from a non-vue source
const helpers = [...helperImports].filter(i => !userImports[i])
@@ -897,7 +899,7 @@ function walkDeclaration(
init &&
init.type === 'CallExpression' &&
init.callee.type === 'Identifier' &&
init.callee.name === USE_OPTIONS
init.callee.name === DEFINE_OPTIONS
)
if (id.type === 'Identifier') {
bindings[id.name] =