]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: custom directive compat
authorEvan You <yyx990803@gmail.com>
Tue, 6 Apr 2021 15:57:10 +0000 (11:57 -0400)
committerEvan You <yyx990803@gmail.com>
Wed, 7 Apr 2021 20:19:24 +0000 (16:19 -0400)
packages/runtime-core/src/compat/customDirective.ts [new file with mode: 0644]
packages/runtime-core/src/compat/deprecations.ts
packages/runtime-core/src/compat/global.ts
packages/runtime-core/src/directives.ts

diff --git a/packages/runtime-core/src/compat/customDirective.ts b/packages/runtime-core/src/compat/customDirective.ts
new file mode 100644 (file)
index 0000000..f7ae36e
--- /dev/null
@@ -0,0 +1,49 @@
+import { isArray } from '@vue/shared/src'
+import { ObjectDirective, DirectiveHook } from '../directives'
+import { DeprecationTypes, warnDeprecation } from './deprecations'
+
+export interface LegacyDirective {
+  bind?: DirectiveHook
+  inserted?: DirectiveHook
+  update?: DirectiveHook
+  componentUpdated?: DirectiveHook
+  unbind?: DirectiveHook
+}
+
+const legacyDirectiveHookMap: Partial<
+  Record<
+    keyof ObjectDirective,
+    keyof LegacyDirective | (keyof LegacyDirective)[]
+  >
+> = {
+  beforeMount: 'bind',
+  mounted: 'inserted',
+  updated: ['update', 'componentUpdated'],
+  unmounted: 'unbind'
+}
+
+export function mapCompatDirectiveHook(
+  name: keyof ObjectDirective,
+  dir: ObjectDirective & LegacyDirective
+): DirectiveHook | DirectiveHook[] | undefined {
+  const mappedName = legacyDirectiveHookMap[name]
+  if (mappedName) {
+    if (isArray(mappedName)) {
+      const hook: DirectiveHook[] = []
+      mappedName.forEach(name => {
+        const mappedHook = dir[name]
+        if (mappedHook) {
+          __DEV__ &&
+            warnDeprecation(DeprecationTypes.CUSTOM_DIR, mappedName, name)
+          hook.push(mappedHook)
+        }
+      })
+      return hook.length ? hook : undefined
+    } else {
+      if (__DEV__ && dir[mappedName]) {
+        warnDeprecation(DeprecationTypes.CUSTOM_DIR, mappedName, name)
+      }
+      return dir[mappedName]
+    }
+  }
+}
index 44fd443854842cef69eafbaba9089d27417ce2cc..4dda842d64ab48046c767232a8c4b0120da2cffe 100644 (file)
@@ -24,7 +24,9 @@ export const enum DeprecationTypes {
   OPTIONS_BEFORE_DESTROY,
   OPTIONS_DESTROYED,
 
-  PROPS_DEFAULT_THIS
+  PROPS_DEFAULT_THIS,
+
+  CUSTOM_DIR
 }
 
 type DeprecationData = {
@@ -157,6 +159,13 @@ const deprecations: Record<DeprecationTypes, DeprecationData> = {
       `props default value function no longer has access to "this". ` +
       `(found in prop "${key}")`,
     link: `https://v3.vuejs.org/guide/migration/props-default-this.html`
+  },
+
+  [DeprecationTypes.CUSTOM_DIR]: {
+    message: (legacyHook: string, newHook: string) =>
+      `Custom directive hook "${legacyHook}" has been removed. ` +
+      `Use "${newHook}" instead.`,
+    link: `https://v3.vuejs.org/guide/migration/custom-directives.html`
   }
 }
 
index 5f09239caddfdec146933d65537de70ba104f1ab..68b1bb53aecd49c23d24a7f56c2eab8d22c7d293 100644 (file)
@@ -28,6 +28,7 @@ import { nextTick } from '../scheduler'
 import { warnDeprecation, DeprecationTypes } from './deprecations'
 import { version } from '..'
 import { LegacyConfig } from './globalConfig'
+import { LegacyDirective } from './customDirective'
 
 /**
  * @deprecated the default `Vue` export has been removed in Vue 3. The type for
@@ -94,6 +95,12 @@ export function createCompatVue(
   function createCompatApp(options: ComponentOptions = {}, Ctor: any) {
     const app = createApp(options)
 
+    // copy over asset registries and deopt flag
+    ;['mixins', 'components', 'directives', 'deopt'].forEach(key => {
+      // @ts-ignore
+      app._context[key] = singletonApp._context[key]
+    })
+
     // copy over global config mutations
     isCopyingConfig = true
     for (const key in singletonApp.config) {
@@ -184,7 +191,7 @@ export function createCompatVue(
     return Vue
   }
 
-  Vue.component = ((name: string, comp: any) => {
+  Vue.component = ((name: string, comp: Component) => {
     if (comp) {
       singletonApp.component(name, comp)
       return Vue
@@ -193,9 +200,9 @@ export function createCompatVue(
     }
   }) as any
 
-  Vue.directive = ((name: string, dir: any) => {
+  Vue.directive = ((name: string, dir: Directive | LegacyDirective) => {
     if (dir) {
-      singletonApp.directive(name, dir)
+      singletonApp.directive(name, dir as Directive)
       return Vue
     } else {
       return singletonApp.directive(name)
index 20f25d03ee9f4a36fafec18131e6553b7efa27d2..69b3d3ad4ee017c2b189d330f5f854827f94226a 100644 (file)
@@ -18,6 +18,7 @@ import { ComponentInternalInstance, Data } from './component'
 import { currentRenderingInstance } from './componentRenderContext'
 import { callWithAsyncErrorHandling, ErrorCodes } from './errorHandling'
 import { ComponentPublicInstance } from './componentPublicInstance'
+import { mapCompatDirectiveHook } from './compat/customDirective'
 
 export interface DirectiveBinding<V = any> {
   instance: ComponentPublicInstance | null
@@ -124,7 +125,10 @@ export function invokeDirectiveHook(
     if (oldBindings) {
       binding.oldValue = oldBindings[i].value
     }
-    const hook = binding.dir[name] as DirectiveHook | undefined
+    let hook = binding.dir[name] as DirectiveHook | DirectiveHook[] | undefined
+    if (__COMPAT__ && !hook) {
+      hook = mapCompatDirectiveHook(name, binding.dir)
+    }
     if (hook) {
       callWithAsyncErrorHandling(hook, instance, ErrorCodes.DIRECTIVE_HOOK, [
         vnode.el,