]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor: transformHArgs -> transformVNodeArgs
authorEvan You <yyx990803@gmail.com>
Mon, 23 Mar 2020 20:54:28 +0000 (16:54 -0400)
committerEvan You <yyx990803@gmail.com>
Mon, 23 Mar 2020 20:54:28 +0000 (16:54 -0400)
packages/runtime-core/__tests__/h.spec.ts
packages/runtime-core/__tests__/vnode.spec.ts
packages/runtime-core/src/h.ts
packages/runtime-core/src/index.ts
packages/runtime-core/src/vnode.ts

index 4358043207ff318c56bc9ca7d1a0bfc15b7a9674..b55c9f4820b0e9beb024124ad6b8f5aa0d3085b4 100644 (file)
@@ -1,11 +1,9 @@
-import { h, transformHArgs, resetTransformHArgs } from '../src/h'
+import { h } from '../src/h'
 import { createVNode } from '../src/vnode'
-import { ComponentInternalInstance } from '@vue/runtime-core'
-import { createApp } from '@vue/runtime-dom'
 
 // Since h is a thin layer on top of createVNode, we are only testing its
 // own logic here. Details of vnode creation is tested in vnode.spec.ts.
-const testH = () => {
+describe('renderer: h', () => {
   test('type only', () => {
     expect(h('div')).toMatchObject(createVNode('div'))
   })
@@ -59,62 +57,4 @@ const testH = () => {
       })
     )
   })
-}
-
-describe('renderer: h', testH)
-
-describe('renderer: transformHArgs', () => {
-  describe('no-op pass-through', () => {
-    beforeAll(() => {
-      transformHArgs((hArgs: unknown[]) => hArgs)
-    })
-    afterAll(resetTransformHArgs)
-    testH()
-  })
-
-  describe('args is used directly, without merging', () => {
-    beforeAll(() => {
-      transformHArgs(() => ['h1', 'Hello World'])
-    })
-    afterAll(resetTransformHArgs)
-    test('nodes become an h1 with text inside', () => {
-      expect(h('div')).toMatchObject(createVNode('h1', null, 'Hello World'))
-    })
-
-    test('resetting transformHArgs turns things back to normal', () => {
-      expect(h('div')).toMatchObject(createVNode('h1', null, 'Hello World'))
-      resetTransformHArgs()
-      expect(h('div')).toMatchObject(createVNode('div'))
-    })
-  })
-
-  test('receives component instance as the 2nd arg', () => {
-    transformHArgs((_: unknown[], instance: ComponentInternalInstance) => {
-      return ['h1', instance.type.name] // <h1>{{ name }}</h1>
-    })
-
-    const vm = createApp({
-      // this will be the name of the component in the h1
-      name: 'Root Component',
-      render() {
-        return h({
-          // this code will never execute,
-          // because it is overridden by the transformHArgs method
-          render() {
-            return h('h2', 'Stub Text')
-          }
-        })
-      }
-    })
-
-    // we need to mount everything so that the instance passed to
-    // transformHArgs isn't null
-    vm.mount('body')
-
-    expect(document.body.outerHTML).toContain('<h1>Root Component</h1>')
-  })
 })
index 7c11c2ab9c7b5e7434bcfe9ed0622fd6461f8fc7..b89934566e8ff82f02adba3c5a0bb9597112cfec 100644 (file)
@@ -7,10 +7,13 @@ import {
   Text,
   cloneVNode,
   mergeProps,
-  normalizeVNode
+  normalizeVNode,
+  transformVNodeArgs
 } from '../src/vnode'
 import { Data } from '../src/component'
 import { ShapeFlags, PatchFlags } from '@vue/shared'
+import { h } from '../src'
+import { createApp, nodeOps, serializeInner } from '@vue/runtime-test'
 
 describe('vnode', () => {
   test('create with just tag', () => {
@@ -335,4 +338,53 @@ describe('vnode', () => {
       expect(vnode.dynamicChildren).toStrictEqual([vnode1])
     })
   })
+
+  describe('transformVNodeArgs', () => {
+    afterEach(() => {
+      // reset
+      transformVNodeArgs()
+    })
+
+    test('no-op pass through', () => {
+      transformVNodeArgs(args => args)
+      const vnode = createVNode('div', { id: 'foo' }, 'hello')
+      expect(vnode).toMatchObject({
+        type: 'div',
+        props: { id: 'foo' },
+        children: 'hello',
+        shapeFlag: ShapeFlags.ELEMENT | ShapeFlags.TEXT_CHILDREN
+      })
+    })
+
+    test('direct override', () => {
+      transformVNodeArgs(() => ['div', { id: 'foo' }, 'hello'])
+      const vnode = createVNode('p')
+      expect(vnode).toMatchObject({
+        type: 'div',
+        props: { id: 'foo' },
+        children: 'hello',
+        shapeFlag: ShapeFlags.ELEMENT | ShapeFlags.TEXT_CHILDREN
+      })
+    })
+
+    test('receive component instance as 2nd arg', () => {
+      transformVNodeArgs((args, instance) => {
+        if (instance) {
+          return ['h1', null, instance.type.name]
+        } else {
+          return args
+        }
+      })
+      const App = {
+        // this will be the name of the component in the h1
+        name: 'Root Component',
+        render() {
+          return h('p') // this will be overwritten by the transform
+        }
+      }
+      const root = nodeOps.createElement('div')
+      createApp(App).mount(root)
+      expect(serializeInner(root)).toBe('<h1>Root Component</h1>')
+    })
+  })
 })
index 0e53d414be665e5e6ef4ce395cb24c60606c96bb..e6f07fb1f1f861ef979a47c3ab4a9d5497c5348c 100644 (file)
@@ -18,7 +18,6 @@ import {
   ComponentOptions
 } from './apiOptions'
 import { ExtractPropTypes } from './componentProps'
-import { currentRenderingInstance } from './componentRenderUtils'
 
 // `h` is a more user-friendly version of `createVNode` that allows omitting the
 // props when possible. It is intended for manually written render functions.
@@ -78,52 +77,52 @@ interface Constructor<P = any> {
 // manually written render functions.
 
 // element
-function _h(type: string, children?: RawChildren): VNode
-function _h(
+export function h(type: string, children?: RawChildren): VNode
+export function h(
   type: string,
   props?: RawProps | null,
   children?: RawChildren
 ): VNode
 
 // fragment
-function _h(type: typeof Fragment, children?: VNodeArrayChildren): VNode
-function _h(
+export function h(type: typeof Fragment, children?: VNodeArrayChildren): VNode
+export function h(
   type: typeof Fragment,
   props?: RawProps | null,
   children?: VNodeArrayChildren
 ): VNode
 
 // portal (target prop is required)
-function _h(
+export function h(
   type: typeof Portal,
   props: RawProps & PortalProps,
   children: RawChildren
 ): VNode
 
 // suspense
-function _h(type: typeof Suspense, children?: RawChildren): VNode
-function _h(
+export function h(type: typeof Suspense, children?: RawChildren): VNode
+export function h(
   type: typeof Suspense,
   props?: (RawProps & SuspenseProps) | null,
   children?: RawChildren | RawSlots
 ): VNode
 
 // functional component
-function _h(type: FunctionalComponent, children?: RawChildren): VNode
-function _h<P>(
+export function h(type: FunctionalComponent, children?: RawChildren): VNode
+export function h<P>(
   type: FunctionalComponent<P>,
   props?: (RawProps & P) | ({} extends P ? null : never),
   children?: RawChildren | RawSlots
 ): VNode
 
 // stateful component
-function _h(type: ComponentOptions, children?: RawChildren): VNode
-function _h(
+export function h(type: ComponentOptions, children?: RawChildren): VNode
+export function h(
   type: ComponentOptionsWithoutProps | ComponentOptionsWithArrayProps,
   props?: RawProps | null,
   children?: RawChildren | RawSlots
 ): VNode
-function _h<O>(
+export function h<O>(
   type: ComponentOptionsWithObjectProps<O>,
   props?:
     | (RawProps & ExtractPropTypes<O>)
@@ -132,15 +131,15 @@ function _h<O>(
 ): VNode
 
 // fake constructor type returned by `defineComponent` or class component
-function _h(type: Constructor, children?: RawChildren): VNode
-function _h<P>(
+export function h(type: Constructor, children?: RawChildren): VNode
+export function h<P>(
   type: Constructor<P>,
   props?: (RawProps & P) | ({} extends P ? null : never),
   children?: RawChildren | RawSlots
 ): VNode
 
 // Actual implementation
-function _h(type: any, propsOrChildren?: any, children?: any): VNode {
+export function h(type: any, propsOrChildren?: any, children?: any): VNode {
   if (arguments.length === 2) {
     if (isObject(propsOrChildren) && !isArray(propsOrChildren)) {
       // single vnode without props
@@ -160,24 +159,3 @@ function _h(type: any, propsOrChildren?: any, children?: any): VNode {
     return createVNode(type, propsOrChildren, children)
   }
 }
-
-export const h: typeof _h = __DEV__ ? (applyTransformedH as typeof _h) : _h
-
-let argsTransformer: Function | undefined
-
-// This is used to hook into the h function and transform its arguments
-// Useful for re-implementing behavior that was previously done with createElement in Vue 2
-function applyTransformedH(...args: unknown[]): VNode {
-  if (argsTransformer) {
-    args = argsTransformer(args, currentRenderingInstance)
-  }
-  return _h(...(args as Parameters<typeof _h>))
-}
-
-export function transformHArgs(transformer: Function): void {
-  argsTransformer = transformer
-}
-
-export function resetTransformHArgs(): void {
-  argsTransformer = undefined
-}
index 9ca4ecd1f3266485916a231c1733a1471cee2a8c..d6be3c56645581e0245288dc47641b79a40cdbde 100644 (file)
@@ -109,6 +109,9 @@ export { toDisplayString, camelize } from '@vue/shared'
 // For integration with runtime compiler
 export { registerRuntimeCompiler } from './component'
 
+// For test-utils
+export { transformVNodeArgs } from './vnode'
+
 // SSR -------------------------------------------------------------------------
 
 import { createComponentInstance, setupComponent } from './component'
index 78599e63c440c37ffe9f26777235f9beb3493b74..709781867d94a32ce4d102139765c0ae8ca4ee53 100644 (file)
@@ -211,7 +211,32 @@ export function isSameVNodeType(n1: VNode, n2: VNode): boolean {
   return n1.type === n2.type && n1.key === n2.key
 }
 
-export function createVNode(
+let vnodeArgsTransformer:
+  | ((
+      args: Parameters<typeof _createVNode>,
+      instance: ComponentInternalInstance | null
+    ) => Parameters<typeof _createVNode>)
+  | undefined
+
+// Internal API for registering an arguments transform for createVNode
+// used for creating stubs in the test-utils
+export function transformVNodeArgs(transformer?: typeof vnodeArgsTransformer) {
+  vnodeArgsTransformer = transformer
+}
+
+const createVNodeWithArgsTransform = (
+  ...args: Parameters<typeof _createVNode>
+): VNode => {
+  return _createVNode(
+    ...(vnodeArgsTransformer
+      ? vnodeArgsTransformer(args, currentRenderingInstance)
+      : args)
+  )
+}
+
+export const createVNode = __DEV__ ? createVNodeWithArgsTransform : _createVNode
+
+function _createVNode(
   type: VNodeTypes | ClassComponent,
   props: (Data & VNodeProps) | null = null,
   children: unknown = null,