Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(compiler-sfc): support resolve enum member for defineEmits #8475

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,30 @@ return { myEmit }
}"
`;

exports[`defineEmits > w/ enum member 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
enum Foo { Foo = 'foo', Bar = 'bar', Qux = 'qux' }
export type FooRef = Bar.Foo

interface Emits {
(e: FooRef, value: string): void;
(e: Foo.Bar, value: string): void;
}

export default /*@__PURE__*/_defineComponent({
emits: ["foo", "bar"],
setup(__props, { expose: __expose, emit: __emit }) {
__expose();

enum Bar { Foo = Foo.Foo }
const emit = __emit

return { Foo, Bar, emit }
}

})"
`;

exports[`defineEmits > w/ runtime options 1`] = `
"import { defineComponent as _defineComponent } from 'vue'

Expand Down
18 changes: 18 additions & 0 deletions packages/compiler-sfc/__tests__/compileScript/defineEmits.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,24 @@ const emit = defineEmits(['a', 'b'])
expect(content).toMatch(`emits: ["foo", "bar"]`)
})

test('w/ enum member', () => {
const { content } = compile(`
<script setup lang="ts">
enum Foo { Foo = 'foo', Bar = 'bar', Qux = 'qux' }
enum Bar { Foo = Foo.Foo }
export type FooRef = Bar.Foo

interface Emits {
(e: FooRef, value: string): void;
(e: Foo.Bar, value: string): void;
}
const emit = defineEmits<Emits>()
</script>
`)
assertCode(content)
expect(content).toMatch(`emits: ["foo", "bar"]`)
})

test('w/ type from normal script', () => {
const { content } = compile(`
<script lang="ts">
Expand Down
37 changes: 36 additions & 1 deletion packages/compiler-sfc/src/script/defineEmits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import { isCallOf } from './utils'
import type { ScriptCompileContext } from './context'
import {
type TypeResolveContext,
resolveEnumMemberValue,
resolveTypeElements,
resolveTypeReference,
resolveUnionType,
} from './resolveType'

Expand Down Expand Up @@ -112,7 +114,8 @@ function extractEventNames(
eventName.typeAnnotation &&
eventName.typeAnnotation.type === 'TSTypeAnnotation'
) {
const types = resolveUnionType(ctx, eventName.typeAnnotation.typeAnnotation)
const typeNode = eventName.typeAnnotation.typeAnnotation
const types = resolveUnionType(ctx, typeNode)

for (const type of types) {
if (type.type === 'TSLiteralType') {
Expand All @@ -122,6 +125,38 @@ function extractEventNames(
) {
emits.add(String(type.literal.value))
}
} else if (type.type === 'TSEnumDeclaration') {
edison1105 marked this conversation as resolved.
Show resolved Hide resolved
if (
typeNode.type === 'TSTypeReference' &&
typeNode.typeName.type === 'TSQualifiedName'
) {
const memberValue = resolveEnumMemberValue(
ctx,
type,
typeNode.typeName.right.name,
)
if (memberValue) emits.add(memberValue)
}
} else if (type.type === 'TSTypeReference') {
if (
type.typeName.type === 'TSQualifiedName' &&
type.typeName.left.type === 'Identifier'
) {
const resolved = resolveTypeReference(
ctx,
type,
undefined,
type.typeName.left.name,
)
if (resolved && resolved.type === 'TSEnumDeclaration') {
const memberValue = resolveEnumMemberValue(
ctx,
resolved,
type.typeName.right.name,
)
if (memberValue) emits.add(memberValue)
}
}
}
}
}
Expand Down
92 changes: 75 additions & 17 deletions packages/compiler-sfc/src/script/resolveType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -699,8 +699,9 @@ type ReferenceTypes =
| TSExpressionWithTypeArguments
| TSImportType
| TSTypeQuery
| Identifier

function resolveTypeReference(
export function resolveTypeReference(
ctx: TypeResolveContext,
node: ReferenceTypes & {
_resolvedReference?: ScopeTypeNode
Expand Down Expand Up @@ -759,21 +760,35 @@ function innerResolveTypeReference(
}
}
} else {
let ns = innerResolveTypeReference(ctx, scope, name[0], node, onlyExported)
if (ns) {
if (ns.type !== 'TSModuleDeclaration') {
// namespace merged with other types, attached as _ns
ns = ns._ns
}
if (ns) {
const childScope = moduleDeclToScope(ctx, ns, ns._ownerScope || scope)
return innerResolveTypeReference(
ctx,
childScope,
name.length > 2 ? name.slice(1) : name[name.length - 1],
node,
!ns.declare,
)
let resolved = innerResolveTypeReference(
ctx,
scope,
name[0],
node,
onlyExported,
)
if (resolved) {
if (resolved.type === 'TSEnumDeclaration') {
return resolved
} else {
if (resolved.type !== 'TSModuleDeclaration') {
// namespace merged with other types, attached as _ns
resolved = resolved._ns
}
if (resolved) {
const childScope = moduleDeclToScope(
ctx,
resolved,
resolved._ownerScope || scope,
)
return innerResolveTypeReference(
ctx,
childScope,
name.length > 2 ? name.slice(1) : name[name.length - 1],
node,
!resolved.declare,
)
}
}
}
}
Expand All @@ -787,7 +802,9 @@ function getReferenceName(node: ReferenceTypes): string | string[] {
? node.expression
: node.type === 'TSImportType'
? node.qualifier
: node.exprName
: node.type === 'TSTypeQuery'
? node.exprName
: node
if (ref?.type === 'Identifier') {
return ref.name
} else if (ref?.type === 'TSQualifiedName') {
Expand Down Expand Up @@ -1941,3 +1958,44 @@ export function resolveUnionType(

return types
}

export function resolveEnumMemberValue(
ctx: TypeResolveContext,
node: Node & MaybeWithScope & { _resolvedElements?: ResolvedElements },
typeName: string,
scope?: TypeScope,
): string | undefined {
if (node.type === 'TSTypeReference') {
const resolved = resolveTypeReference(ctx, node, scope, typeName)
if (resolved) node = resolved
}

if (node.type === 'Identifier') {
const resolved = resolveTypeReference(ctx, node, scope, node.name)
if (resolved) node = resolved
}

if (node.type === 'TSEnumDeclaration') {
for (const m of node.members) {
if (m.id.type === 'Identifier' && m.id.name === typeName) {
if (m.initializer) {
if (m.initializer.type === 'StringLiteral') {
return m.initializer.value
} else if (m.initializer.type === 'MemberExpression') {
if (
m.initializer.object.type === 'Identifier' &&
m.initializer.property.type === 'Identifier'
) {
return resolveEnumMemberValue(
ctx,
m.initializer.object,
m.initializer.property.name,
scope,
)
}
}
}
}
}
}
}
Loading