]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(compat): maintain compatConfig option in legacy functional comp (#4974)
authorIllya Klymov <xanf@xanf.me>
Mon, 6 Dec 2021 04:20:27 +0000 (06:20 +0200)
committerGitHub <noreply@github.com>
Mon, 6 Dec 2021 04:20:27 +0000 (23:20 -0500)
packages/runtime-core/src/compat/componentFunctional.ts
packages/runtime-core/src/component.ts
packages/vue-compat/__tests__/componentFunctional.spec.ts

index 80af32a1dae4b37f8c4928ddf7d47206b377815f..1b1146bbab94ae8c6585c0edec2769d2f4c1194b 100644 (file)
@@ -55,6 +55,7 @@ export function convertLegacyFunctionalComponent(comp: ComponentOptions) {
   }
   Func.props = comp.props
   Func.displayName = comp.name
+  Func.compatConfig = comp.compatConfig
   // v2 functional components do not inherit attrs
   Func.inheritAttrs = false
 
index 515bd16d2f3d5c07476a5cd3eb62ec6f86f49935..cda15d8bd0741a27fb2ce62a5bd4d05e6775b0b1 100644 (file)
@@ -60,7 +60,11 @@ import { markAttrsAccessed } from './componentRenderUtils'
 import { currentRenderingInstance } from './componentRenderContext'
 import { startMeasure, endMeasure } from './profiling'
 import { convertLegacyRenderFn } from './compat/renderFn'
-import { globalCompatConfig, validateCompatConfig } from './compat/compatConfig'
+import {
+  CompatConfig,
+  globalCompatConfig,
+  validateCompatConfig
+} from './compat/compatConfig'
 import { SchedulerJob } from './scheduler'
 
 export type Data = Record<string, unknown>
@@ -111,6 +115,7 @@ export interface FunctionalComponent<P = {}, E extends EmitsOptions = {}>
   emits?: E | (keyof E)[]
   inheritAttrs?: boolean
   displayName?: string
+  compatConfig?: CompatConfig
 }
 
 export interface ClassComponent {
index 82587cbf86b474d3e988d9fbaca0815c3d77d506..e17534ce25c336917227691ba71ab25d7e43ae82 100644 (file)
@@ -18,45 +18,80 @@ afterEach(() => {
   Vue.configureCompat({ MODE: 3 })
 })
 
-test('COMPONENT_FUNCTIONAL', async () => {
-  const func = {
-    name: 'Func',
-    functional: true,
-    props: {
-      x: String
-    },
-    inject: ['foo'],
-    render: (h: any, { data, props, injections, slots }: any) => {
-      return h('div', { id: props.x, class: data.class }, [
-        h('div', { class: 'inject' }, injections.foo),
-        h('div', { class: 'slot' }, slots().default)
-      ])
+describe('COMPONENT_FUNCTIONAL', () => {
+  test('basic usage', async () => {
+    const func = {
+      name: 'Func',
+      functional: true,
+      props: {
+        x: String
+      },
+      inject: ['foo'],
+      render: (h: any, { data, props, injections, slots }: any) => {
+        return h('div', { id: props.x, class: data.class }, [
+          h('div', { class: 'inject' }, injections.foo),
+          h('div', { class: 'slot' }, slots().default)
+        ])
+      }
     }
-  }
 
-  const vm = new Vue({
-    provide() {
-      return {
-        foo: 123
+    const vm = new Vue({
+      provide() {
+        return {
+          foo: 123
+        }
+      },
+      components: {
+        func
+      },
+      template: `<func class="foo" x="foo">hello</func>`
+    }).$mount()
+
+    expect(vm.$el.id).toBe('foo')
+    expect(vm.$el.className).toBe('foo')
+    expect(vm.$el.querySelector('.inject').textContent).toBe('123')
+    expect(vm.$el.querySelector('.slot').textContent).toBe('hello')
+    expect(vm.$el.outerHTML).toMatchInlineSnapshot(
+      `"<div id=\\"foo\\" class=\\"foo\\"><div class=\\"inject\\">123</div><div class=\\"slot\\">hello</div></div>"`
+    )
+
+    expect(
+      (
+        deprecationData[DeprecationTypes.COMPONENT_FUNCTIONAL]
+          .message as Function
+      )(func)
+    ).toHaveBeenWarned()
+  })
+
+  test('copies compatConfig option', () => {
+    const func = {
+      name: 'Func',
+      functional: true,
+      compatConfig: {
+        ATTR_FALSE_VALUE: 'suppress-warning' as const
+      },
+      render: (h: any) => {
+        // should not render required: false due to compatConfig
+        return h('div', { 'data-some-attr': false })
       }
-    },
-    components: {
-      func
-    },
-    template: `<func class="foo" x="foo">hello</func>`
-  }).$mount()
-
-  expect(vm.$el.id).toBe('foo')
-  expect(vm.$el.className).toBe('foo')
-  expect(vm.$el.querySelector('.inject').textContent).toBe('123')
-  expect(vm.$el.querySelector('.slot').textContent).toBe('hello')
-  expect(vm.$el.outerHTML).toMatchInlineSnapshot(
-    `"<div id=\\"foo\\" class=\\"foo\\"><div class=\\"inject\\">123</div><div class=\\"slot\\">hello</div></div>"`
-  )
-
-  expect(
-    (
-      deprecationData[DeprecationTypes.COMPONENT_FUNCTIONAL].message as Function
-    )(func)
-  ).toHaveBeenWarned()
+    }
+
+    const vm = new Vue({
+      components: { func },
+      template: `<func class="foo" x="foo">hello</func>`
+    }).$mount()
+
+    expect(vm.$el.outerHTML).toMatchInlineSnapshot(`"<div></div>"`)
+    expect(
+      (
+        deprecationData[DeprecationTypes.COMPONENT_FUNCTIONAL]
+          .message as Function
+      )(func)
+    ).toHaveBeenWarned()
+    expect(
+      (deprecationData[DeprecationTypes.ATTR_FALSE_VALUE].message as Function)(
+        func
+      )
+    ).not.toHaveBeenWarned()
+  })
 })