Skip to content

Commit 2238925

Browse files
dssengyyx990803
authored andcommitted
feat(core): validate directives names (vuejs#326)
1 parent 60961ef commit 2238925

File tree

4 files changed

+55
-4
lines changed

4 files changed

+55
-4
lines changed

packages/runtime-core/__tests__/apiApp.spec.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ describe('api: createApp', () => {
138138
expect(spy1).toHaveBeenCalled()
139139
expect(spy2).not.toHaveBeenCalled()
140140
expect(spy3).toHaveBeenCalled()
141+
142+
app.directive('bind', FooBar)
143+
expect(
144+
`Do not use built-in directive ids as custom directive id: bind`
145+
).toHaveBeenWarned()
141146
})
142147

143148
test('mixin', () => {
@@ -342,6 +347,33 @@ describe('api: createApp', () => {
342347
).toHaveBeenWarned()
343348
})
344349

350+
test('Component.directives', () => {
351+
const app = createApp()
352+
Object.defineProperty(app.config, 'isNativeTag', {
353+
value: isNativeTag,
354+
writable: false
355+
})
356+
357+
const Root = {
358+
directives: {
359+
bind: () => {}
360+
},
361+
setup() {
362+
return {
363+
count: ref(0)
364+
}
365+
},
366+
render() {
367+
return null
368+
}
369+
}
370+
371+
app.mount(Root, nodeOps.createElement('div'))
372+
expect(
373+
`Do not use built-in directive ids as custom directive id: bind`
374+
).toHaveBeenWarned()
375+
})
376+
345377
test('register using app.component', () => {
346378
const app = createApp()
347379
Object.defineProperty(app.config, 'isNativeTag', {

packages/runtime-core/src/apiApp.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Component, Data, validateComponentName } from './component'
22
import { ComponentOptions } from './apiOptions'
33
import { ComponentPublicInstance } from './componentProxy'
4-
import { Directive } from './directives'
4+
import { Directive, validateDirectiveName } from './directives'
55
import { RootRenderFunction } from './createRenderer'
66
import { InjectionKey } from './apiInject'
77
import { isFunction, NO } from '@vue/shared'
@@ -127,7 +127,10 @@ export function createAppAPI<HostNode, HostElement>(
127127
},
128128

129129
directive(name: string, directive?: Directive) {
130-
// TODO directive name validation
130+
if (__DEV__) {
131+
validateDirectiveName(name)
132+
}
133+
131134
if (!directive) {
132135
return context.directives[name] as any
133136
} else {

packages/runtime-core/src/component.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import {
1313
callWithAsyncErrorHandling
1414
} from './errorHandling'
1515
import { AppContext, createAppContext, AppConfig } from './apiApp'
16-
import { Directive } from './directives'
16+
import { Directive, validateDirectiveName } from './directives'
1717
import { applyOptions, ComponentOptions } from './apiOptions'
1818
import {
1919
EMPTY_OBJ,
@@ -256,6 +256,12 @@ export function setupStatefulComponent(
256256
validateComponentName(name, instance.appContext.config)
257257
}
258258
}
259+
if (Component.directives) {
260+
const names = Object.keys(Component.directives)
261+
for (let i = 0; i < names.length; i++) {
262+
validateDirectiveName(names[i])
263+
}
264+
}
259265
}
260266
// 0. create render proxy property access cache
261267
instance.accessCache = {}

packages/runtime-core/src/directives.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ return applyDirectives(h(comp), [
1212
*/
1313

1414
import { VNode, cloneVNode } from './vnode'
15-
import { extend, isArray, isFunction, EMPTY_OBJ } from '@vue/shared'
15+
import { extend, isArray, isFunction, EMPTY_OBJ, makeMap } from '@vue/shared'
1616
import { warn } from './warning'
1717
import { ComponentInternalInstance } from './component'
1818
import { currentRenderingInstance } from './componentRenderUtils'
@@ -51,6 +51,16 @@ type DirectiveModifiers = Record<string, boolean>
5151

5252
const valueCache = new WeakMap<Directive, WeakMap<any, any>>()
5353

54+
const isBuiltInDirective = /*#__PURE__*/ makeMap(
55+
'bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text'
56+
)
57+
58+
export function validateDirectiveName(name: string) {
59+
if (isBuiltInDirective(name)) {
60+
warn('Do not use built-in directive ids as custom directive id: ' + name)
61+
}
62+
}
63+
5464
function applyDirective(
5565
props: Record<any, any>,
5666
instance: ComponentInternalInstance,

0 commit comments

Comments
 (0)