Skip to content

Commit 38adf4d

Browse files
authored
Merge pull request #151 from cexbrayat/refactor/find-stub-anonymous-component
refactor: properly find/stub anonymous component
2 parents 2412a8d + 0d0874e commit 38adf4d

File tree

3 files changed

+48
-18
lines changed

3 files changed

+48
-18
lines changed

src/stubs.ts

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { hyphenate } from './utils/vueShared'
1212
import { MOUNT_COMPONENT_REF, MOUNT_PARENT_NAME } from './constants'
1313
import { config } from './config'
1414
import { matchName } from './utils/matchName'
15+
import { ComponentInternalInstance } from '@vue/runtime-core'
1516

1617
interface StubOptions {
1718
name?: string
@@ -74,18 +75,7 @@ export function stubComponents(
7475
stubs: Record<any, any> = {},
7576
shallow: boolean = false
7677
) {
77-
transformVNodeArgs((args) => {
78-
const locallyRegisteredComponents = (args[0] as any).components as
79-
| Record<string, VNodeTypes>
80-
| undefined
81-
if (locallyRegisteredComponents) {
82-
for (const registrationName in locallyRegisteredComponents) {
83-
const component = locallyRegisteredComponents[registrationName]
84-
if (!component['name'] && !component['displayName']) {
85-
component['name'] = registrationName
86-
}
87-
}
88-
}
78+
transformVNodeArgs((args, instance: ComponentInternalInstance | null) => {
8979
const [nodeType, props, children, patchFlag, dynamicProps] = args
9080
const type = nodeType as VNodeTypes
9181
// args[0] can either be:
@@ -102,7 +92,19 @@ export function stubComponents(
10292
}
10393

10494
if (isComponent(type) || isFunctionalComponent(type)) {
105-
const name = type['name'] || type['displayName']
95+
let name = type['name'] || type['displayName']
96+
97+
// if no name, then check the locally registered components in the parent
98+
if (!name && instance && instance.parent) {
99+
// try to infer the name based on local resolution
100+
const registry = (instance.type as any).components
101+
for (const key in registry) {
102+
if (registry[key] === type) {
103+
name = key
104+
break
105+
}
106+
}
107+
}
106108
if (!name && !shallow) {
107109
return args
108110
}

src/utils/find.ts

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,40 @@ function matches(node: VNode, selector: FindAllComponentsSelector): boolean {
2121
return node.el?.matches?.(selector)
2222
}
2323

24-
if (typeof selector === 'object' && typeof node.type === 'object') {
25-
if (selector === node.type) return true
24+
const nodeType = node.type
25+
if (typeof selector === 'object' && typeof nodeType === 'object') {
26+
// we are looking for this exact component
27+
if (selector === nodeType) {
28+
return true
29+
}
2630

27-
if (selector.name && ('name' in node.type || 'displayName' in node.type)) {
31+
let componentName
32+
if ('name' in nodeType || 'displayName' in nodeType) {
2833
// match normal component definitions or functional components
29-
return matchName(selector.name, node.type.name || node.type.displayName)
34+
componentName = nodeType.name || nodeType.displayName
35+
}
36+
let selectorName = selector.name
37+
38+
// the component and selector both have a name
39+
if (componentName && selectorName) {
40+
return matchName(selectorName, componentName)
41+
}
42+
43+
// if a name is missing, then check the locally registered components in the parent
44+
if (node.component.parent) {
45+
const registry = (node.component.parent as any).components
46+
for (const key in registry) {
47+
// is it the selector
48+
if (!selectorName && registry[key] === selector) {
49+
selectorName = key
50+
}
51+
// is it the component
52+
if (!componentName && registry[key] === nodeType) {
53+
componentName = key
54+
}
55+
}
56+
// we may have one or both missing names
57+
return matchName(selectorName, componentName)
3058
}
3159
}
3260

src/utils/matchName.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { camelize, capitalize } from './vueShared'
22

3-
export function matchName(target, sourceName) {
3+
export function matchName(target: string, sourceName: string) {
44
const camelized = camelize(target)
55
const capitalized = capitalize(camelized)
66

0 commit comments

Comments
 (0)