feat(core): validate directives names (#326)
This commit is contained in:
parent
60961ef5b6
commit
2238925fbe
@ -138,6 +138,11 @@ describe('api: createApp', () => {
|
|||||||
expect(spy1).toHaveBeenCalled()
|
expect(spy1).toHaveBeenCalled()
|
||||||
expect(spy2).not.toHaveBeenCalled()
|
expect(spy2).not.toHaveBeenCalled()
|
||||||
expect(spy3).toHaveBeenCalled()
|
expect(spy3).toHaveBeenCalled()
|
||||||
|
|
||||||
|
app.directive('bind', FooBar)
|
||||||
|
expect(
|
||||||
|
`Do not use built-in directive ids as custom directive id: bind`
|
||||||
|
).toHaveBeenWarned()
|
||||||
})
|
})
|
||||||
|
|
||||||
test('mixin', () => {
|
test('mixin', () => {
|
||||||
@ -342,6 +347,33 @@ describe('api: createApp', () => {
|
|||||||
).toHaveBeenWarned()
|
).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', () => {
|
test('register using app.component', () => {
|
||||||
const app = createApp()
|
const app = createApp()
|
||||||
Object.defineProperty(app.config, 'isNativeTag', {
|
Object.defineProperty(app.config, 'isNativeTag', {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, Data, validateComponentName } from './component'
|
import { Component, Data, validateComponentName } from './component'
|
||||||
import { ComponentOptions } from './apiOptions'
|
import { ComponentOptions } from './apiOptions'
|
||||||
import { ComponentPublicInstance } from './componentProxy'
|
import { ComponentPublicInstance } from './componentProxy'
|
||||||
import { Directive } from './directives'
|
import { Directive, validateDirectiveName } from './directives'
|
||||||
import { RootRenderFunction } from './createRenderer'
|
import { RootRenderFunction } from './createRenderer'
|
||||||
import { InjectionKey } from './apiInject'
|
import { InjectionKey } from './apiInject'
|
||||||
import { isFunction, NO } from '@vue/shared'
|
import { isFunction, NO } from '@vue/shared'
|
||||||
@ -127,7 +127,10 @@ export function createAppAPI<HostNode, HostElement>(
|
|||||||
},
|
},
|
||||||
|
|
||||||
directive(name: string, directive?: Directive) {
|
directive(name: string, directive?: Directive) {
|
||||||
// TODO directive name validation
|
if (__DEV__) {
|
||||||
|
validateDirectiveName(name)
|
||||||
|
}
|
||||||
|
|
||||||
if (!directive) {
|
if (!directive) {
|
||||||
return context.directives[name] as any
|
return context.directives[name] as any
|
||||||
} else {
|
} else {
|
||||||
|
@ -13,7 +13,7 @@ import {
|
|||||||
callWithAsyncErrorHandling
|
callWithAsyncErrorHandling
|
||||||
} from './errorHandling'
|
} from './errorHandling'
|
||||||
import { AppContext, createAppContext, AppConfig } from './apiApp'
|
import { AppContext, createAppContext, AppConfig } from './apiApp'
|
||||||
import { Directive } from './directives'
|
import { Directive, validateDirectiveName } from './directives'
|
||||||
import { applyOptions, ComponentOptions } from './apiOptions'
|
import { applyOptions, ComponentOptions } from './apiOptions'
|
||||||
import {
|
import {
|
||||||
EMPTY_OBJ,
|
EMPTY_OBJ,
|
||||||
@ -256,6 +256,12 @@ export function setupStatefulComponent(
|
|||||||
validateComponentName(name, instance.appContext.config)
|
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
|
// 0. create render proxy property access cache
|
||||||
instance.accessCache = {}
|
instance.accessCache = {}
|
||||||
|
@ -12,7 +12,7 @@ return applyDirectives(h(comp), [
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { VNode, cloneVNode } from './vnode'
|
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 { warn } from './warning'
|
||||||
import { ComponentInternalInstance } from './component'
|
import { ComponentInternalInstance } from './component'
|
||||||
import { currentRenderingInstance } from './componentRenderUtils'
|
import { currentRenderingInstance } from './componentRenderUtils'
|
||||||
@ -51,6 +51,16 @@ type DirectiveModifiers = Record<string, boolean>
|
|||||||
|
|
||||||
const valueCache = new WeakMap<Directive, WeakMap<any, any>>()
|
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(
|
function applyDirective(
|
||||||
props: Record<any, any>,
|
props: Record<any, any>,
|
||||||
instance: ComponentInternalInstance,
|
instance: ComponentInternalInstance,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user