/
defineEmits.ts
118 lines (105 loc) 路 3.02 KB
/
defineEmits.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
import { Identifier, LVal, Node, RestElement } from '@babel/types'
import { isCallOf } from './utils'
import { ScriptCompileContext } from './context'
import { resolveTypeElements, resolveUnionType } from './resolveType'
export const DEFINE_EMITS = 'defineEmits'
export function processDefineEmits(
ctx: ScriptCompileContext,
node: Node,
declId?: LVal
): boolean {
if (!isCallOf(node, DEFINE_EMITS)) {
return false
}
if (ctx.hasDefineEmitCall) {
ctx.error(`duplicate ${DEFINE_EMITS}() call`, node)
}
ctx.hasDefineEmitCall = true
ctx.emitsRuntimeDecl = node.arguments[0]
if (node.typeParameters) {
if (ctx.emitsRuntimeDecl) {
ctx.error(
`${DEFINE_EMITS}() cannot accept both type and non-type arguments ` +
`at the same time. Use one or the other.`,
node
)
}
ctx.emitsTypeDecl = node.typeParameters.params[0]
}
if (declId) {
ctx.emitIdentifier =
declId.type === 'Identifier' ? declId.name : ctx.getString(declId)
}
return true
}
export function genRuntimeEmits(ctx: ScriptCompileContext): string | undefined {
let emitsDecl = ''
if (ctx.emitsRuntimeDecl) {
emitsDecl = ctx.getString(ctx.emitsRuntimeDecl).trim()
} else if (ctx.emitsTypeDecl) {
const typeDeclaredEmits = extractRuntimeEmits(ctx)
emitsDecl = typeDeclaredEmits.size
? `[${Array.from(typeDeclaredEmits)
.map(k => JSON.stringify(k))
.join(', ')}]`
: ``
}
if (ctx.hasDefineModelCall) {
let modelEmitsDecl = `[${Object.keys(ctx.modelDecls)
.map(n => JSON.stringify(`update:${n}`))
.join(', ')}]`
emitsDecl = emitsDecl
? `${ctx.helper('mergeModels')}(${emitsDecl}, ${modelEmitsDecl})`
: modelEmitsDecl
}
return emitsDecl
}
function extractRuntimeEmits(ctx: ScriptCompileContext): Set<string> {
const emits = new Set<string>()
const node = ctx.emitsTypeDecl!
if (node.type === 'TSFunctionType') {
extractEventNames(ctx, node.parameters[0], emits)
return emits
}
const { props, calls } = resolveTypeElements(ctx, node)
let hasProperty = false
for (const key in props) {
emits.add(key)
hasProperty = true
}
if (calls) {
if (hasProperty) {
ctx.error(
`defineEmits() type cannot mixed call signature and property syntax.`,
node
)
}
for (const call of calls) {
extractEventNames(ctx, call.parameters[0], emits)
}
}
return emits
}
function extractEventNames(
ctx: ScriptCompileContext,
eventName: Identifier | RestElement,
emits: Set<string>
) {
if (
eventName.type === 'Identifier' &&
eventName.typeAnnotation &&
eventName.typeAnnotation.type === 'TSTypeAnnotation'
) {
const types = resolveUnionType(ctx, eventName.typeAnnotation.typeAnnotation)
for (const type of types) {
if (type.type === 'TSLiteralType') {
if (
type.literal.type !== 'UnaryExpression' &&
type.literal.type !== 'TemplateLiteral'
) {
emits.add(String(type.literal.value))
}
}
}
}
}