wip: extract runtime props/emits from type declarations

This commit is contained in:
Evan You 2020-07-07 20:23:53 -04:00
parent 608885350b
commit c0d86070fd

View File

@ -58,7 +58,6 @@ export function compileScriptSetup(
const scriptStartOffset = script && script.loc.start.offset const scriptStartOffset = script && script.loc.start.offset
const scriptEndOffset = script && script.loc.end.offset const scriptEndOffset = script && script.loc.end.offset
// parse and transform <script setup>
const isTS = scriptSetup.lang === 'ts' const isTS = scriptSetup.lang === 'ts'
const plugins: ParserPlugin[] = [ const plugins: ParserPlugin[] = [
...(options.parserPlugins || []), ...(options.parserPlugins || []),
@ -66,7 +65,7 @@ export function compileScriptSetup(
...(isTS ? (['typescript'] as const) : []) ...(isTS ? (['typescript'] as const) : [])
] ]
// process normal <script> first if it exists // 1. process normal <script> first if it exists
if (script) { if (script) {
// import dedupe between <script> and <script setup> // import dedupe between <script> and <script setup>
const scriptAST = parse(script.content, { const scriptAST = parse(script.content, {
@ -108,7 +107,7 @@ export function compileScriptSetup(
} }
} }
// check <script setup="xxx"> function signature // 2. check <script setup="xxx"> function signature
const hasExplicitSignature = typeof scriptSetup.setup === 'string' const hasExplicitSignature = typeof scriptSetup.setup === 'string'
let propsVar = `$props` let propsVar = `$props`
let emitVar = `$emit` let emitVar = `$emit`
@ -124,8 +123,8 @@ export function compileScriptSetup(
let setupCtxASTNode let setupCtxASTNode
// props/emits declared via types // props/emits declared via types
const typeDeclaredProps: string[] = [] const typeDeclaredProps: Set<string> = new Set()
const typeDeclaredEmits: string[] = [] const typeDeclaredEmits: Set<string> = new Set()
if (isTS && hasExplicitSignature) { if (isTS && hasExplicitSignature) {
// <script setup="xxx" lang="ts"> // <script setup="xxx" lang="ts">
@ -159,13 +158,11 @@ export function compileScriptSetup(
} }
} }
const scriptSetupAST = parse(scriptSetup.content, { // 3. parse <script setup> and walk over top level statements
for (const node of parse(scriptSetup.content, {
plugins, plugins,
sourceType: 'module' sourceType: 'module'
}).program.body }).program.body) {
// walk over top level statements
for (const node of scriptSetupAST) {
const start = node.start! + startOffset const start = node.start! + startOffset
let end = node.end! + startOffset let end = node.end! + startOffset
// import or type declarations: move to top // import or type declarations: move to top
@ -436,11 +433,34 @@ export function compileScriptSetup(
s.appendRight(endOffset, `\nreturn ${returned}\n}\n\n`) s.appendRight(endOffset, `\nreturn ${returned}\n}\n\n`)
// finalize default export
if (isTS) {
// for TS, make sure the exported type is still valid type with
// correct props information
s.prepend(`import { defineComponent as __define__ } from 'vue'\n`)
// we have to use object spread for types to be merged properly
// user's TS setting should compile it down to proper targets
const def = defaultExport ? `\n ...__default__,` : ``
const runtimeProps = typeDeclaredProps.size
? `\n props: [${Array.from(typeDeclaredProps)
.map(p => JSON.stringify(p))
.join(', ')}] as unknown as undefined,`
: ``
const runtimeEmits = typeDeclaredEmits.size
? `\n emits: [${Array.from(typeDeclaredEmits)
.map(p => JSON.stringify(p))
.join(', ')}] as unknown as undefined,`
: ``
s.append(
`export default __define__({${def}${runtimeProps}${runtimeEmits}\n setup\n})`
)
} else {
if (defaultExport) { if (defaultExport) {
s.append(`__default__.setup = setup\nexport default __default__`) s.append(`__default__.setup = setup\nexport default __default__`)
} else { } else {
s.append(`export default { setup }`) s.append(`export default { setup }`)
} }
}
s.trim() s.trim()
@ -536,17 +556,36 @@ function walkPattern(node: Node, bindings: Record<string, boolean>) {
} }
} }
function extractProps(node: TSTypeLiteral, props: string[]) { function extractProps(node: TSTypeLiteral, props: Set<string>) {
// TODO for (const m of node.members) {
console.log('gen props', node, props) if (m.type === 'TSPropertySignature' && m.key.type === 'Identifier') {
props.add(m.key.name)
}
}
} }
function extractEmits( function extractEmits(
node: TSFunctionType | TSDeclareFunction, node: TSFunctionType | TSDeclareFunction,
emits: string[] emits: Set<string>
) { ) {
// TODO const eventName =
console.log('gen emits', node, emits) node.type === 'TSDeclareFunction' ? node.params[0] : node.parameters[0]
if (
eventName.type === 'Identifier' &&
eventName.typeAnnotation &&
eventName.typeAnnotation.type === 'TSTypeAnnotation'
) {
const typeNode = eventName.typeAnnotation.typeAnnotation
if (typeNode.type === 'TSLiteralType') {
emits.add(String(typeNode.literal.value))
} else if (typeNode.type === 'TSUnionType') {
for (const t of typeNode.types) {
if (t.type === 'TSLiteralType') {
emits.add(String(t.literal.value))
}
}
}
}
} }
/** /**