]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
wip: filter emits
authorEvan You <evan@vuejs.org>
Tue, 3 Dec 2024 09:20:07 +0000 (17:20 +0800)
committerEvan You <evan@vuejs.org>
Tue, 3 Dec 2024 09:20:07 +0000 (17:20 +0800)
packages/runtime-core/src/componentEmits.ts
packages/runtime-core/src/index.ts
packages/runtime-vapor/src/_new/component.ts
packages/runtime-vapor/src/_new/componentEmits.ts [new file with mode: 0644]
packages/runtime-vapor/src/_new/componentProps.ts

index db52bc88c333e02176c4da3409ea89177879250d..abeb74a6d466998804c344a469004316ffdd6c4f 100644 (file)
@@ -282,9 +282,13 @@ export function normalizeEmitsOptions(
   return normalized
 }
 
-// Check if an incoming prop key is a declared emit event listener.
-// e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are
-// both considered matched listeners.
+/**
+ * Check if an incoming prop key is a declared emit event listener.
+ * e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are
+ * both considered matched listeners.
+ *
+ * @internal for vapor only
+ */
 export function isEmitListener(
   options: ObjectEmitsOptions | null,
   key: string,
index d9af62eee8f15574a1ff6859ebfd7c3978feb952..9ff31e6d456774cab24c3ca868386464af51c7ba 100644 (file)
@@ -488,4 +488,5 @@ export const DeprecationTypes = (
 // change without notice between versions. User code should never rely on them.
 
 export { baseNormalizePropsOptions, resolvePropValue } from './componentProps'
+export { isEmitListener } from './componentEmits'
 export { type SchedulerJob, queueJob } from './scheduler'
index 2e27d4fc7daeb9866bf9b4ac17d4ae2ff661b6e9..e3281f2fd4b1a6dfc06ab9b06a37098d53524da9 100644 (file)
@@ -3,6 +3,7 @@ import {
   EffectScope,
   type EmitsOptions,
   type NormalizedPropsOptions,
+  type ObjectEmitsOptions,
 } from '@vue/runtime-core'
 import type { Block } from '../block'
 import type { Data } from '@vue/runtime-shared'
@@ -44,6 +45,7 @@ export interface ObjectComponent
 interface SharedInternalOptions {
   __propsOptions?: NormalizedPropsOptions
   __propsHandlers?: [ProxyHandler<any>, ProxyHandler<any>]
+  __emitsOptions?: ObjectEmitsOptions
 }
 
 // Note: can't mark this whole interface internal because some public interfaces
diff --git a/packages/runtime-vapor/src/_new/componentEmits.ts b/packages/runtime-vapor/src/_new/componentEmits.ts
new file mode 100644 (file)
index 0000000..c07c44c
--- /dev/null
@@ -0,0 +1,26 @@
+import type { ObjectEmitsOptions } from '@vue/runtime-core'
+import type { Component } from './component'
+import { isArray } from '@vue/shared'
+
+/**
+ * The logic from core isn't too reusable so it's better to duplicate here
+ */
+export function normalizeEmitsOptions(
+  comp: Component,
+): ObjectEmitsOptions | null {
+  const cached = comp.__emitsOptions
+  if (cached) return cached
+
+  const raw = comp.emits
+  if (!raw) return null
+
+  let normalized: ObjectEmitsOptions
+  if (isArray(raw)) {
+    normalized = {}
+    for (const key in raw) normalized[key] = null
+  } else {
+    normalized = raw
+  }
+
+  return (comp.__emitsOptions = normalized)
+}
index 03f6082e48dd3ad79cf3a93bf360258a068c2a38..105639725a4924ae753ccd5e7f1e260f05c6929c 100644 (file)
@@ -3,8 +3,10 @@ import type { Component, ComponentInstance } from './component'
 import {
   type NormalizedPropsOptions,
   baseNormalizePropsOptions,
+  isEmitListener,
   resolvePropValue,
 } from '@vue/runtime-core'
+import { normalizeEmitsOptions } from './componentEmits'
 
 export interface RawProps {
   [key: string]: PropSource
@@ -23,7 +25,7 @@ export function initStaticProps(
   let hasAttrs = false
   const { props, attrs } = instance
   const [propsOptions, needCastKeys] = normalizePropsOptions(comp)
-  // TODO emits filtering
+  const emitsOptions = normalizeEmitsOptions(comp)
   for (const key in rawProps) {
     const normalizedKey = camelize(key)
     const needCast = needCastKeys && needCastKeys.includes(normalizedKey)
@@ -54,7 +56,7 @@ export function initStaticProps(
             )
           : source
       }
-    } else {
+    } else if (!isEmitListener(emitsOptions, key)) {
       if (isFunction(source)) {
         Object.defineProperty(attrs, key, {
           enumerable: true,
@@ -102,44 +104,48 @@ export function getDynamicPropsHandlers(
   }
   let normalizedKeys: string[] | undefined
   const propsOptions = normalizePropsOptions(comp)[0]!
-  const isProp = (key: string | symbol) => hasOwn(propsOptions, key)
-
-  const getProp = (target: RawProps, key: string | symbol, asProp: boolean) => {
-    if (key !== '$' && (asProp ? isProp(key) : !isProp(key))) {
-      const castProp = (value: any, isAbsent = false) =>
-        asProp
-          ? resolvePropValue(
-              propsOptions,
-              key as string,
-              value,
-              instance,
-              resolveDefault,
-              isAbsent,
-            )
-          : value
-
-      if (key in target) {
-        // TODO default value, casting, etc.
-        return castProp(resolveSource(target[key as string]))
-      }
-      if (target.$) {
-        let i = target.$.length
-        let source
-        while (i--) {
-          source = resolveSource(target.$[i])
-          if (hasOwn(source, key)) {
-            return castProp(source[key])
-          }
+  const emitsOptions = normalizeEmitsOptions(comp)
+  const isProp = (key: string) => hasOwn(propsOptions, key)
+
+  const getProp = (target: RawProps, key: string, asProp: boolean) => {
+    if (key === '$') return
+    if (asProp) {
+      if (!isProp(key)) return
+    } else if (isProp(key) || isEmitListener(emitsOptions, key)) {
+      return
+    }
+    const castProp = (value: any, isAbsent = false) =>
+      asProp
+        ? resolvePropValue(
+            propsOptions,
+            key as string,
+            value,
+            instance,
+            resolveDefault,
+            isAbsent,
+          )
+        : value
+
+    if (key in target) {
+      return castProp(resolveSource(target[key as string]))
+    }
+    if (target.$) {
+      let i = target.$.length
+      let source
+      while (i--) {
+        source = resolveSource(target.$[i])
+        if (hasOwn(source, key)) {
+          return castProp(source[key])
         }
       }
-      return castProp(undefined, true)
     }
+    return castProp(undefined, true)
   }
 
   const propsHandlers = {
-    get: (target, key) => getProp(target, key, true),
-    has: (_, key) => isProp(key),
-    getOwnPropertyDescriptor(target, key) {
+    get: (target, key: string) => getProp(target, key, true),
+    has: (_, key: string) => isProp(key),
+    getOwnPropertyDescriptor(target, key: string) {
       if (isProp(key)) {
         return {
           configurable: true,
@@ -154,8 +160,9 @@ export function getDynamicPropsHandlers(
     deleteProperty: NO,
   } satisfies ProxyHandler<RawProps>
 
-  const hasAttr = (target: RawProps, key: string | symbol) => {
-    if (key === '$' || isProp(key)) return false
+  const hasAttr = (target: RawProps, key: string) => {
+    if (key === '$' || isProp(key) || isEmitListener(emitsOptions, key))
+      return false
     if (hasOwn(target, key)) return true
     if (target.$) {
       let i = target.$.length
@@ -169,9 +176,9 @@ export function getDynamicPropsHandlers(
   }
 
   const attrsHandlers = {
-    get: (target, key) => getProp(target, key, false),
+    get: (target, key: string) => getProp(target, key, false),
     has: hasAttr,
-    getOwnPropertyDescriptor(target, key) {
+    getOwnPropertyDescriptor(target, key: string) {
       if (hasAttr(target, key)) {
         return {
           configurable: true,
@@ -181,16 +188,14 @@ export function getDynamicPropsHandlers(
       }
     },
     ownKeys(target) {
-      const staticKeys = Object.keys(target).filter(
-        key => key !== '$' && !isProp(key),
-      )
+      const staticKeys = Object.keys(target)
       if (target.$) {
         let i = target.$.length
         while (i--) {
           staticKeys.push(...Object.keys(resolveSource(target.$[i])))
         }
       }
-      return staticKeys
+      return staticKeys.filter(key => hasAttr(target, key))
     },
     set: NO,
     deleteProperty: NO,