mirror of https://github.com/vuejs/core.git
wip: filter emits
This commit is contained in:
parent
9d89d7ab27
commit
4ea66770be
|
@ -282,9 +282,13 @@ export function normalizeEmitsOptions(
|
||||||
return normalized
|
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
|
* Check if an incoming prop key is a declared emit event listener.
|
||||||
// both considered matched listeners.
|
* e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are
|
||||||
|
* both considered matched listeners.
|
||||||
|
*
|
||||||
|
* @internal for vapor only
|
||||||
|
*/
|
||||||
export function isEmitListener(
|
export function isEmitListener(
|
||||||
options: ObjectEmitsOptions | null,
|
options: ObjectEmitsOptions | null,
|
||||||
key: string,
|
key: string,
|
||||||
|
|
|
@ -488,4 +488,5 @@ export const DeprecationTypes = (
|
||||||
// change without notice between versions. User code should never rely on them.
|
// change without notice between versions. User code should never rely on them.
|
||||||
|
|
||||||
export { baseNormalizePropsOptions, resolvePropValue } from './componentProps'
|
export { baseNormalizePropsOptions, resolvePropValue } from './componentProps'
|
||||||
|
export { isEmitListener } from './componentEmits'
|
||||||
export { type SchedulerJob, queueJob } from './scheduler'
|
export { type SchedulerJob, queueJob } from './scheduler'
|
||||||
|
|
|
@ -3,6 +3,7 @@ import {
|
||||||
EffectScope,
|
EffectScope,
|
||||||
type EmitsOptions,
|
type EmitsOptions,
|
||||||
type NormalizedPropsOptions,
|
type NormalizedPropsOptions,
|
||||||
|
type ObjectEmitsOptions,
|
||||||
} from '@vue/runtime-core'
|
} from '@vue/runtime-core'
|
||||||
import type { Block } from '../block'
|
import type { Block } from '../block'
|
||||||
import type { Data } from '@vue/runtime-shared'
|
import type { Data } from '@vue/runtime-shared'
|
||||||
|
@ -44,6 +45,7 @@ export interface ObjectComponent
|
||||||
interface SharedInternalOptions {
|
interface SharedInternalOptions {
|
||||||
__propsOptions?: NormalizedPropsOptions
|
__propsOptions?: NormalizedPropsOptions
|
||||||
__propsHandlers?: [ProxyHandler<any>, ProxyHandler<any>]
|
__propsHandlers?: [ProxyHandler<any>, ProxyHandler<any>]
|
||||||
|
__emitsOptions?: ObjectEmitsOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: can't mark this whole interface internal because some public interfaces
|
// Note: can't mark this whole interface internal because some public interfaces
|
||||||
|
|
|
@ -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)
|
||||||
|
}
|
|
@ -3,8 +3,10 @@ import type { Component, ComponentInstance } from './component'
|
||||||
import {
|
import {
|
||||||
type NormalizedPropsOptions,
|
type NormalizedPropsOptions,
|
||||||
baseNormalizePropsOptions,
|
baseNormalizePropsOptions,
|
||||||
|
isEmitListener,
|
||||||
resolvePropValue,
|
resolvePropValue,
|
||||||
} from '@vue/runtime-core'
|
} from '@vue/runtime-core'
|
||||||
|
import { normalizeEmitsOptions } from './componentEmits'
|
||||||
|
|
||||||
export interface RawProps {
|
export interface RawProps {
|
||||||
[key: string]: PropSource
|
[key: string]: PropSource
|
||||||
|
@ -23,7 +25,7 @@ export function initStaticProps(
|
||||||
let hasAttrs = false
|
let hasAttrs = false
|
||||||
const { props, attrs } = instance
|
const { props, attrs } = instance
|
||||||
const [propsOptions, needCastKeys] = normalizePropsOptions(comp)
|
const [propsOptions, needCastKeys] = normalizePropsOptions(comp)
|
||||||
// TODO emits filtering
|
const emitsOptions = normalizeEmitsOptions(comp)
|
||||||
for (const key in rawProps) {
|
for (const key in rawProps) {
|
||||||
const normalizedKey = camelize(key)
|
const normalizedKey = camelize(key)
|
||||||
const needCast = needCastKeys && needCastKeys.includes(normalizedKey)
|
const needCast = needCastKeys && needCastKeys.includes(normalizedKey)
|
||||||
|
@ -54,7 +56,7 @@ export function initStaticProps(
|
||||||
)
|
)
|
||||||
: source
|
: source
|
||||||
}
|
}
|
||||||
} else {
|
} else if (!isEmitListener(emitsOptions, key)) {
|
||||||
if (isFunction(source)) {
|
if (isFunction(source)) {
|
||||||
Object.defineProperty(attrs, key, {
|
Object.defineProperty(attrs, key, {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
|
@ -102,44 +104,48 @@ export function getDynamicPropsHandlers(
|
||||||
}
|
}
|
||||||
let normalizedKeys: string[] | undefined
|
let normalizedKeys: string[] | undefined
|
||||||
const propsOptions = normalizePropsOptions(comp)[0]!
|
const propsOptions = normalizePropsOptions(comp)[0]!
|
||||||
const isProp = (key: string | symbol) => hasOwn(propsOptions, key)
|
const emitsOptions = normalizeEmitsOptions(comp)
|
||||||
|
const isProp = (key: string) => hasOwn(propsOptions, key)
|
||||||
|
|
||||||
const getProp = (target: RawProps, key: string | symbol, asProp: boolean) => {
|
const getProp = (target: RawProps, key: string, asProp: boolean) => {
|
||||||
if (key !== '$' && (asProp ? isProp(key) : !isProp(key))) {
|
if (key === '$') return
|
||||||
const castProp = (value: any, isAbsent = false) =>
|
if (asProp) {
|
||||||
asProp
|
if (!isProp(key)) return
|
||||||
? resolvePropValue(
|
} else if (isProp(key) || isEmitListener(emitsOptions, key)) {
|
||||||
propsOptions,
|
return
|
||||||
key as string,
|
}
|
||||||
value,
|
const castProp = (value: any, isAbsent = false) =>
|
||||||
instance,
|
asProp
|
||||||
resolveDefault,
|
? resolvePropValue(
|
||||||
isAbsent,
|
propsOptions,
|
||||||
)
|
key as string,
|
||||||
: value
|
value,
|
||||||
|
instance,
|
||||||
|
resolveDefault,
|
||||||
|
isAbsent,
|
||||||
|
)
|
||||||
|
: value
|
||||||
|
|
||||||
if (key in target) {
|
if (key in target) {
|
||||||
// TODO default value, casting, etc.
|
return castProp(resolveSource(target[key as string]))
|
||||||
return castProp(resolveSource(target[key as string]))
|
}
|
||||||
}
|
if (target.$) {
|
||||||
if (target.$) {
|
let i = target.$.length
|
||||||
let i = target.$.length
|
let source
|
||||||
let source
|
while (i--) {
|
||||||
while (i--) {
|
source = resolveSource(target.$[i])
|
||||||
source = resolveSource(target.$[i])
|
if (hasOwn(source, key)) {
|
||||||
if (hasOwn(source, key)) {
|
return castProp(source[key])
|
||||||
return castProp(source[key])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return castProp(undefined, true)
|
|
||||||
}
|
}
|
||||||
|
return castProp(undefined, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
const propsHandlers = {
|
const propsHandlers = {
|
||||||
get: (target, key) => getProp(target, key, true),
|
get: (target, key: string) => getProp(target, key, true),
|
||||||
has: (_, key) => isProp(key),
|
has: (_, key: string) => isProp(key),
|
||||||
getOwnPropertyDescriptor(target, key) {
|
getOwnPropertyDescriptor(target, key: string) {
|
||||||
if (isProp(key)) {
|
if (isProp(key)) {
|
||||||
return {
|
return {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
|
@ -154,8 +160,9 @@ export function getDynamicPropsHandlers(
|
||||||
deleteProperty: NO,
|
deleteProperty: NO,
|
||||||
} satisfies ProxyHandler<RawProps>
|
} satisfies ProxyHandler<RawProps>
|
||||||
|
|
||||||
const hasAttr = (target: RawProps, key: string | symbol) => {
|
const hasAttr = (target: RawProps, key: string) => {
|
||||||
if (key === '$' || isProp(key)) return false
|
if (key === '$' || isProp(key) || isEmitListener(emitsOptions, key))
|
||||||
|
return false
|
||||||
if (hasOwn(target, key)) return true
|
if (hasOwn(target, key)) return true
|
||||||
if (target.$) {
|
if (target.$) {
|
||||||
let i = target.$.length
|
let i = target.$.length
|
||||||
|
@ -169,9 +176,9 @@ export function getDynamicPropsHandlers(
|
||||||
}
|
}
|
||||||
|
|
||||||
const attrsHandlers = {
|
const attrsHandlers = {
|
||||||
get: (target, key) => getProp(target, key, false),
|
get: (target, key: string) => getProp(target, key, false),
|
||||||
has: hasAttr,
|
has: hasAttr,
|
||||||
getOwnPropertyDescriptor(target, key) {
|
getOwnPropertyDescriptor(target, key: string) {
|
||||||
if (hasAttr(target, key)) {
|
if (hasAttr(target, key)) {
|
||||||
return {
|
return {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
|
@ -181,16 +188,14 @@ export function getDynamicPropsHandlers(
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ownKeys(target) {
|
ownKeys(target) {
|
||||||
const staticKeys = Object.keys(target).filter(
|
const staticKeys = Object.keys(target)
|
||||||
key => key !== '$' && !isProp(key),
|
|
||||||
)
|
|
||||||
if (target.$) {
|
if (target.$) {
|
||||||
let i = target.$.length
|
let i = target.$.length
|
||||||
while (i--) {
|
while (i--) {
|
||||||
staticKeys.push(...Object.keys(resolveSource(target.$[i])))
|
staticKeys.push(...Object.keys(resolveSource(target.$[i])))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return staticKeys
|
return staticKeys.filter(key => hasAttr(target, key))
|
||||||
},
|
},
|
||||||
set: NO,
|
set: NO,
|
||||||
deleteProperty: NO,
|
deleteProperty: NO,
|
||||||
|
|
Loading…
Reference in New Issue