]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(core): validate directives names (#326)
authorDmitry Sharshakov <d3dx12.xx@gmail.com>
Fri, 18 Oct 2019 16:34:45 +0000 (19:34 +0300)
committerEvan You <yyx990803@gmail.com>
Fri, 18 Oct 2019 16:34:45 +0000 (12:34 -0400)
packages/runtime-core/__tests__/apiApp.spec.ts
packages/runtime-core/src/apiApp.ts
packages/runtime-core/src/component.ts
packages/runtime-core/src/directives.ts

index 3eb340206caf75947946ba0857d9b8dbacf7a21d..4bcf3614a895edd2823a7d344b0bc829e1ee2afb 100644 (file)
@@ -138,6 +138,11 @@ describe('api: createApp', () => {
     expect(spy1).toHaveBeenCalled()
     expect(spy2).not.toHaveBeenCalled()
     expect(spy3).toHaveBeenCalled()
+
+    app.directive('bind', FooBar)
+    expect(
+      `Do not use built-in directive ids as custom directive id: bind`
+    ).toHaveBeenWarned()
   })
 
   test('mixin', () => {
@@ -342,6 +347,33 @@ describe('api: createApp', () => {
       ).toHaveBeenWarned()
     })
 
+    test('Component.directives', () => {
+      const app = createApp()
+      Object.defineProperty(app.config, 'isNativeTag', {
+        value: isNativeTag,
+        writable: false
+      })
+
+      const Root = {
+        directives: {
+          bind: () => {}
+        },
+        setup() {
+          return {
+            count: ref(0)
+          }
+        },
+        render() {
+          return null
+        }
+      }
+
+      app.mount(Root, nodeOps.createElement('div'))
+      expect(
+        `Do not use built-in directive ids as custom directive id: bind`
+      ).toHaveBeenWarned()
+    })
+
     test('register using app.component', () => {
       const app = createApp()
       Object.defineProperty(app.config, 'isNativeTag', {
index 31d61047aa15c1a749dae902e302a5662c1f9a50..18afa463e842fc927b227e61fc77da99d0355a3c 100644 (file)
@@ -1,7 +1,7 @@
 import { Component, Data, validateComponentName } from './component'
 import { ComponentOptions } from './apiOptions'
 import { ComponentPublicInstance } from './componentProxy'
-import { Directive } from './directives'
+import { Directive, validateDirectiveName } from './directives'
 import { RootRenderFunction } from './createRenderer'
 import { InjectionKey } from './apiInject'
 import { isFunction, NO } from '@vue/shared'
@@ -127,7 +127,10 @@ export function createAppAPI<HostNode, HostElement>(
       },
 
       directive(name: string, directive?: Directive) {
-        // TODO directive name validation
+        if (__DEV__) {
+          validateDirectiveName(name)
+        }
+
         if (!directive) {
           return context.directives[name] as any
         } else {
index 5e8539b8c4723576eca585dd7e8b0ef02e6251af..b3dec82fb07e023fb02c408119dbb2fdc60332d1 100644 (file)
@@ -13,7 +13,7 @@ import {
   callWithAsyncErrorHandling
 } from './errorHandling'
 import { AppContext, createAppContext, AppConfig } from './apiApp'
-import { Directive } from './directives'
+import { Directive, validateDirectiveName } from './directives'
 import { applyOptions, ComponentOptions } from './apiOptions'
 import {
   EMPTY_OBJ,
@@ -256,6 +256,12 @@ export function setupStatefulComponent(
         validateComponentName(name, instance.appContext.config)
       }
     }
+    if (Component.directives) {
+      const names = Object.keys(Component.directives)
+      for (let i = 0; i < names.length; i++) {
+        validateDirectiveName(names[i])
+      }
+    }
   }
   // 0. create render proxy property access cache
   instance.accessCache = {}
index 1ab1b0d806170a2cc03b802d93c09040395748e8..01c9a83246c25f3a4a78fa08328a1e2d370fe15c 100644 (file)
@@ -12,7 +12,7 @@ return applyDirectives(h(comp), [
 */
 
 import { VNode, cloneVNode } from './vnode'
-import { extend, isArray, isFunction, EMPTY_OBJ } from '@vue/shared'
+import { extend, isArray, isFunction, EMPTY_OBJ, makeMap } from '@vue/shared'
 import { warn } from './warning'
 import { ComponentInternalInstance } from './component'
 import { currentRenderingInstance } from './componentRenderUtils'
@@ -51,6 +51,16 @@ type DirectiveModifiers = Record<string, boolean>
 
 const valueCache = new WeakMap<Directive, WeakMap<any, any>>()
 
+const isBuiltInDirective = /*#__PURE__*/ makeMap(
+  'bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text'
+)
+
+export function validateDirectiveName(name: string) {
+  if (isBuiltInDirective(name)) {
+    warn('Do not use built-in directive ids as custom directive id: ' + name)
+  }
+}
+
 function applyDirective(
   props: Record<any, any>,
   instance: ComponentInternalInstance,