feat(core): validate directives names (#326)

This commit is contained in:
Dmitry Sharshakov 2019-10-18 19:34:45 +03:00 committed by Evan You
parent 60961ef5b6
commit 2238925fbe
4 changed files with 55 additions and 4 deletions

View 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', {

View 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 {

View 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 = {}

View 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,