Skip to content

Commit

Permalink
fix(runtime-core): do not throw on unknown directives
Browse files Browse the repository at this point in the history
Fixes #6340

This commit improves the case when a directive is not found in a template.
As `resolveDirective` returns `undefined`, some code was failing with the following error:

```
TypeError: Cannot read properties of undefined (reading 'deep')
```
  • Loading branch information
cexbrayat committed Sep 15, 2022
1 parent 8772a01 commit 07b3269
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 22 deletions.
25 changes: 23 additions & 2 deletions packages/runtime-core/__tests__/directives.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
VNode,
DirectiveBinding,
nextTick,
defineComponent
defineComponent,
Directive
} from '@vue/runtime-test'
import { currentInstance, ComponentInternalInstance } from '../src/component'

Expand Down Expand Up @@ -242,7 +243,7 @@ describe('directives', () => {
expect(root.children[0]).toBe(el)

// node should not have been updated yet
// expect(el.children[0].text).toBe(`${count.value - 1}`)
expect(el.children[0].text).toBe(`${count.value - 1}`)

assertBindings(binding)

Expand Down Expand Up @@ -421,4 +422,24 @@ describe('directives', () => {
render(h(App), root)
expect(res!).toBe('Test')
})

test('should not throw with unknown directive', async () => {
const d1 = {
mounted: jest.fn()
}
const App = {
name: 'App',
render() {
// simulates the code generated on an unknown directive
return withDirectives(h('div'), [
[undefined as unknown as Directive],
[d1]
])
}
}

const root = nodeOps.createElement('div')
render(h(App), root)
expect(d1.mounted).toHaveBeenCalled()
})
})
42 changes: 22 additions & 20 deletions packages/runtime-core/src/directives.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,10 +71,10 @@ export function validateDirectiveName(name: string) {

// Directive, value, argument, modifiers
export type DirectiveArguments = Array<
| [Directive]
| [Directive, any]
| [Directive, any, string]
| [Directive, any, string, DirectiveModifiers]
| [Directive | undefined]
| [Directive | undefined, any]
| [Directive | undefined, any, string]
| [Directive | undefined, any, string, DirectiveModifiers]
>

/**
Expand All @@ -95,23 +95,25 @@ export function withDirectives<T extends VNode>(
const bindings: DirectiveBinding[] = vnode.dirs || (vnode.dirs = [])
for (let i = 0; i < directives.length; i++) {
let [dir, value, arg, modifiers = EMPTY_OBJ] = directives[i]
if (isFunction(dir)) {
dir = {
mounted: dir,
updated: dir
} as ObjectDirective
if (dir) {
if (isFunction(dir)) {
dir = {
mounted: dir,
updated: dir
} as ObjectDirective
}
if (dir.deep) {
traverse(value)
}
bindings.push({
dir,
instance,
value,
oldValue: void 0,
arg,
modifiers
})
}
if (dir.deep) {
traverse(value)
}
bindings.push({
dir,
instance,
value,
oldValue: void 0,
arg,
modifiers
})
}
return vnode
}
Expand Down

0 comments on commit 07b3269

Please sign in to comment.