]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(compiler-core): support v-is
authorEvan You <yyx990803@gmail.com>
Fri, 27 Mar 2020 20:38:31 +0000 (16:38 -0400)
committerEvan You <yyx990803@gmail.com>
Fri, 27 Mar 2020 20:38:31 +0000 (16:38 -0400)
see https://github.com/vuejs/rfcs/pull/149 for details

packages/compiler-core/__tests__/parse.spec.ts
packages/compiler-core/__tests__/transforms/transformElement.spec.ts
packages/compiler-core/src/parse.ts
packages/compiler-core/src/transforms/transformElement.ts

index b21288d95c75c6b432b547d4d9e1497d0f72478b..4b0992a5f195e2386fa8a31076fe00a50a4f9f58 100644 (file)
@@ -646,6 +646,55 @@ describe('compiler: parse', () => {
       })
     })
 
+    test('v-is without `isNativeTag`', () => {
+      const ast = baseParse(
+        `<div></div><div v-is="'foo'"></div><Comp></Comp>`,
+        {
+          isNativeTag: tag => tag === 'div'
+        }
+      )
+
+      expect(ast.children[0]).toMatchObject({
+        type: NodeTypes.ELEMENT,
+        tag: 'div',
+        tagType: ElementTypes.ELEMENT
+      })
+
+      expect(ast.children[1]).toMatchObject({
+        type: NodeTypes.ELEMENT,
+        tag: 'div',
+        tagType: ElementTypes.COMPONENT
+      })
+
+      expect(ast.children[2]).toMatchObject({
+        type: NodeTypes.ELEMENT,
+        tag: 'Comp',
+        tagType: ElementTypes.COMPONENT
+      })
+    })
+
+    test('v-is with `isNativeTag`', () => {
+      const ast = baseParse(`<div></div><div v-is="'foo'"></div><Comp></Comp>`)
+
+      expect(ast.children[0]).toMatchObject({
+        type: NodeTypes.ELEMENT,
+        tag: 'div',
+        tagType: ElementTypes.ELEMENT
+      })
+
+      expect(ast.children[1]).toMatchObject({
+        type: NodeTypes.ELEMENT,
+        tag: 'div',
+        tagType: ElementTypes.COMPONENT
+      })
+
+      expect(ast.children[2]).toMatchObject({
+        type: NodeTypes.ELEMENT,
+        tag: 'Comp',
+        tagType: ElementTypes.COMPONENT
+      })
+    })
+
     test('custom element', () => {
       const ast = baseParse('<div></div><comp></comp>', {
         isNativeTag: tag => tag === 'div',
index 43ba48b9a49b35b7d0fa86481faab3f3164f739b..6434b51c81422a28fbb95af4e94396d3b3efcacf 100644 (file)
@@ -829,6 +829,25 @@ describe('compiler: element transform', () => {
         }
       })
     })
+
+    test('v-is', () => {
+      const { node, root } = parseWithBind(`<div v-is="'foo'" />`)
+      expect(root.helpers).toContain(RESOLVE_DYNAMIC_COMPONENT)
+      expect(node).toMatchObject({
+        tag: {
+          callee: RESOLVE_DYNAMIC_COMPONENT,
+          arguments: [
+            {
+              type: NodeTypes.SIMPLE_EXPRESSION,
+              content: `'foo'`,
+              isStatic: false
+            }
+          ]
+        },
+        // should skip v-is runtime check
+        directives: undefined
+      })
+    })
   })
 
   test('<svg> should be forced into blocks', () => {
index a45a7f37b7982f658c63a321bd4e11b3d8b65c74..11cad7f19a8d216f1727e3a75db7870c035a380d 100644 (file)
@@ -451,9 +451,13 @@ function parseTag(
   let tagType = ElementTypes.ELEMENT
   const options = context.options
   if (!context.inPre && !options.isCustomElement(tag)) {
-    if (options.isNativeTag) {
+    const hasVIs = props.some(
+      p => p.type === NodeTypes.DIRECTIVE && p.name === 'is'
+    )
+    if (options.isNativeTag && !hasVIs) {
       if (!options.isNativeTag(tag)) tagType = ElementTypes.COMPONENT
     } else if (
+      hasVIs ||
       isCoreComponent(tag) ||
       (options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||
       /^[A-Z]/.test(tag) ||
index 155c1dcffb37f1fb765e12276488f8447f6edba7..4ae461caf545a15e0a2bc48a09f78a0048e32dea 100644 (file)
@@ -36,7 +36,8 @@ import {
   toValidAssetId,
   findProp,
   isCoreComponent,
-  isBindKey
+  isBindKey,
+  findDir
 } from '../utils'
 import { buildSlots } from './vSlot'
 import { isStaticNode } from './hoistStatic'
@@ -202,7 +203,8 @@ export function resolveComponentType(
   const { tag } = node
 
   // 1. dynamic component
-  const isProp = node.tag === 'component' && findProp(node, 'is')
+  const isProp =
+    node.tag === 'component' ? findProp(node, 'is') : findDir(node, 'is')
   if (isProp) {
     const exp =
       isProp.type === NodeTypes.ATTRIBUTE
@@ -340,8 +342,11 @@ export function buildProps(
       if (name === 'once') {
         continue
       }
-      // skip :is on <component>
-      if (isBind && tag === 'component' && isBindKey(arg, 'is')) {
+      // skip v-is and :is on <component>
+      if (
+        name === 'is' ||
+        (isBind && tag === 'component' && isBindKey(arg, 'is'))
+      ) {
         continue
       }
       // skip v-on in SSR compilation