From f8b2513efd5b8b440663730166085df70ef98f70 Mon Sep 17 00:00:00 2001 From: skirtle <65301168+skirtles-code@users.noreply.github.com> Date: Sun, 27 Nov 2022 02:14:36 +0000 Subject: [PATCH 1/2] dx(runtime-core): check current and parent components in formatComponentName --- .../runtime-core/__tests__/component.spec.ts | 157 ++++++++++++++++++ packages/runtime-core/src/component.ts | 17 +- 2 files changed, 167 insertions(+), 7 deletions(-) create mode 100644 packages/runtime-core/__tests__/component.spec.ts diff --git a/packages/runtime-core/__tests__/component.spec.ts b/packages/runtime-core/__tests__/component.spec.ts new file mode 100644 index 000000000..312279dcd --- /dev/null +++ b/packages/runtime-core/__tests__/component.spec.ts @@ -0,0 +1,157 @@ +import { + ComponentInternalInstance, + getCurrentInstance, + h, + nodeOps, + render +} from '@vue/runtime-test' +import { formatComponentName } from '../src/component' + +describe('formatComponentName', () => { + test('default name', () => { + let instance: ComponentInternalInstance | null = null + const Comp = { + setup() { + instance = getCurrentInstance() + return () => null + } + } + render(h(Comp), nodeOps.createElement('div')) + + expect(formatComponentName(null, Comp)).toBe('Anonymous') + expect(formatComponentName(null, Comp, true)).toBe('App') + expect(formatComponentName(instance, Comp)).toBe('Anonymous') + expect(formatComponentName(instance, Comp, true)).toBe('App') + }) + + test('name option', () => { + let instance: ComponentInternalInstance | null = null + const Comp = { + name: 'number-input', + setup() { + instance = getCurrentInstance() + return () => null + } + } + render(h(Comp), nodeOps.createElement('div')) + + expect(formatComponentName(null, Comp)).toBe('NumberInput') + expect(formatComponentName(instance, Comp, true)).toBe('NumberInput') + }) + + test('self recursive name', () => { + let instance: ComponentInternalInstance | null = null + const Comp = { + components: {} as any, + setup() { + instance = getCurrentInstance() + return () => null + } + } + Comp.components.ToggleButton = Comp + render(h(Comp), nodeOps.createElement('div')) + + expect(formatComponentName(instance, Comp)).toBe('ToggleButton') + }) + + test('name from parent', () => { + let instance: ComponentInternalInstance | null = null + const Comp = { + setup() { + instance = getCurrentInstance() + return () => null + } + } + const Parent = { + components: { + list_item: Comp + }, + render() { + return h(Comp) + } + } + render(h(Parent), nodeOps.createElement('div')) + + expect(formatComponentName(instance, Comp)).toBe('ListItem') + }) + + test('functional components', () => { + const UserAvatar = () => null + expect(formatComponentName(null, UserAvatar)).toBe('UserAvatar') + UserAvatar.displayName = 'UserPicture' + expect(formatComponentName(null, UserAvatar)).toBe('UserPicture') + expect(formatComponentName(null, () => null)).toBe('Anonymous') + }) + + test('Name from file', () => { + const Comp = { + __file: './src/locale-dropdown.vue' + } + + expect(formatComponentName(null, Comp)).toBe('LocaleDropdown') + }) + + test('inferred name', () => { + const Comp = { + __name: 'MainSidebar' + } + + expect(formatComponentName(null, Comp)).toBe('MainSidebar') + }) + + test('global component', () => { + let instance: ComponentInternalInstance | null = null + const Comp = { + setup() { + instance = getCurrentInstance() + return () => null + } + } + render(h(Comp), nodeOps.createElement('div')) + + instance!.appContext.components.FieldLabel = Comp + + expect(formatComponentName(instance, Comp)).toBe('FieldLabel') + }) + + test('name precedence', () => { + let instance: ComponentInternalInstance | null = null + const Dummy = () => null + const Comp: Record = { + components: { Dummy }, + setup() { + instance = getCurrentInstance() + return () => null + } + } + const Parent = { + components: { Dummy } as any, + render() { + return h(Comp) + } + } + render(h(Parent), nodeOps.createElement('div')) + + expect(formatComponentName(instance, Comp)).toBe('Anonymous') + expect(formatComponentName(instance, Comp, true)).toBe('App') + + instance!.appContext.components.CompA = Comp + expect(formatComponentName(instance, Comp)).toBe('CompA') + expect(formatComponentName(instance, Comp, true)).toBe('CompA') + + Parent.components.CompB = Comp + expect(formatComponentName(instance, Comp)).toBe('CompB') + + Comp.components.CompC = Comp + expect(formatComponentName(instance, Comp)).toBe('CompC') + + Comp.__file = './CompD.js' + expect(formatComponentName(instance, Comp)).toBe('CompD') + + Comp.__name = 'CompE' + expect(formatComponentName(instance, Comp)).toBe('CompE') + + Comp.name = 'CompF' + expect(formatComponentName(instance, Comp)).toBe('CompF') + }) +}) diff --git a/packages/runtime-core/src/component.ts b/packages/runtime-core/src/component.ts index 786e3f3a0..3db5a1394 100644 --- a/packages/runtime-core/src/component.ts +++ b/packages/runtime-core/src/component.ts @@ -695,7 +695,7 @@ function setupStatefulComponent( // bail here and wait for re-entry. instance.asyncDep = setupResult if (__DEV__ && !instance.suspense) { - const name = Component.name ?? 'Anonymous' + const name = formatComponentName(instance, Component) warn( `Component <${name}>: setup function returned a promise, but no ` + ` boundary was found in the parent component tree. ` + @@ -980,7 +980,6 @@ export function getComponentName( : Component.name || (includeInferred && Component.__name) } -/* istanbul ignore next */ export function formatComponentName( instance: ComponentInternalInstance | null, Component: ConcreteComponent, @@ -994,9 +993,11 @@ export function formatComponentName( } } - if (!name && instance && instance.parent) { + if (!name && instance) { // try to infer the name based on reverse resolution - const inferFromRegistry = (registry: Record | undefined) => { + const inferFromRegistry = ( + registry: Record | undefined | null + ) => { for (const key in registry) { if (registry[key] === Component) { return key @@ -1004,10 +1005,12 @@ export function formatComponentName( } } name = - inferFromRegistry( - instance.components || + inferFromRegistry(instance.components) || + (instance.parent && + inferFromRegistry( (instance.parent.type as ComponentOptions).components - ) || inferFromRegistry(instance.appContext.components) + )) || + inferFromRegistry(instance.appContext.components) } return name ? classify(name) : isRoot ? `App` : `Anonymous` From d86e73364c9ea0b4f1f009121222af8eef6915b5 Mon Sep 17 00:00:00 2001 From: "autofix-ci[bot]" <114827586+autofix-ci[bot]@users.noreply.github.com> Date: Sat, 30 Dec 2023 18:42:17 +0000 Subject: [PATCH 2/2] [autofix.ci] apply automated fixes --- packages/runtime-core/__tests__/component.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime-core/__tests__/component.spec.ts b/packages/runtime-core/__tests__/component.spec.ts index f1cb378a1..7b29e774a 100644 --- a/packages/runtime-core/__tests__/component.spec.ts +++ b/packages/runtime-core/__tests__/component.spec.ts @@ -1,5 +1,5 @@ import { - ComponentInternalInstance, + type ComponentInternalInstance, getCurrentInstance, h, nodeOps,