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', () => {
).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', {
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'
},
directive(name: string, directive?: Directive) {
- // TODO directive name validation
+ if (__DEV__) {
+ validateDirectiveName(name)
+ }
+
if (!directive) {
return context.directives[name] as any
} else {
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,
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 = {}
*/
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'
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,