Skip to content

Commit 95f6fff

Browse files
committed
chore: Merge branch 'main' into minor
2 parents e8448b0 + 7c49a9c commit 95f6fff

File tree

9 files changed

+149
-11
lines changed

9 files changed

+149
-11
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
## [3.3.13](https://github.com/vuejs/core/compare/v3.3.12...v3.3.13) (2023-12-19)
2+
3+
4+
### Bug Fixes
5+
6+
* **compiler-core:** fix v-on with modifiers on inline expression of undefined ([#9866](https://github.com/vuejs/core/issues/9866)) ([bae79dd](https://github.com/vuejs/core/commit/bae79ddf8564a2da4a5365cfeb8d811990f42335)), closes [#9865](https://github.com/vuejs/core/issues/9865)
7+
* **runtime-dom:** cache event handlers by key/modifiers ([#9851](https://github.com/vuejs/core/issues/9851)) ([04d2c05](https://github.com/vuejs/core/commit/04d2c05054c26b02fbc1d84839b0ed5cd36455b6)), closes [#9849](https://github.com/vuejs/core/issues/9849)
8+
* **types:** extract properties from extended collections ([#9854](https://github.com/vuejs/core/issues/9854)) ([24b1c1d](https://github.com/vuejs/core/commit/24b1c1dd57fd55d998aa231a147500e010b10219)), closes [#9852](https://github.com/vuejs/core/issues/9852)
9+
10+
11+
112
# [3.4.0-beta.3](https://github.com/vuejs/core/compare/v3.3.12...v3.4.0-beta.3) (2023-12-16)
213

314

packages/compiler-core/__tests__/utils.spec.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ describe('isMemberExpression', () => {
9595
expect(fn(`123[a]`)).toBe(true)
9696
expect(fn(`foo() as string`)).toBe(false)
9797
expect(fn(`a + b as string`)).toBe(false)
98+
// #9865
99+
expect(fn('""')).toBe(false)
100+
expect(fn('undefined')).toBe(false)
101+
expect(fn('null')).toBe(false)
98102
})
99103
})
100104

packages/compiler-core/src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,7 @@ export const isMemberExpressionNode = __BROWSER__
163163
return (
164164
ret.type === 'MemberExpression' ||
165165
ret.type === 'OptionalMemberExpression' ||
166-
ret.type === 'Identifier'
166+
(ret.type === 'Identifier' && ret.name !== 'undefined')
167167
)
168168
} catch (e) {
169169
return false

packages/dts-test/reactivity.test-d.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,18 @@ describe('should unwrap Map correctly', () => {
7777
expectType<number>(wm2.get({})!.wrap)
7878
})
7979

80+
describe('should unwrap extended Map correctly', () => {
81+
class ExtendendMap1 extends Map<string, { wrap: Ref<number> }> {
82+
foo = ref('foo')
83+
bar = 1
84+
}
85+
86+
const emap1 = reactive(new ExtendendMap1())
87+
expectType<string>(emap1.foo)
88+
expectType<number>(emap1.bar)
89+
expectType<number>(emap1.get('a')!.wrap)
90+
})
91+
8092
describe('should unwrap Set correctly', () => {
8193
const set = reactive(new Set<Ref<number>>())
8294
expectType<Set<Ref<number>>>(set)
@@ -90,3 +102,14 @@ describe('should unwrap Set correctly', () => {
90102
const ws2 = reactive(new WeakSet<{ wrap: Ref<number> }>())
91103
expectType<WeakSet<{ wrap: number }>>(ws2)
92104
})
105+
106+
describe('should unwrap extended Set correctly', () => {
107+
class ExtendendSet1 extends Set<{ wrap: Ref<number> }> {
108+
foo = ref('foo')
109+
bar = 1
110+
}
111+
112+
const eset1 = reactive(new ExtendendSet1())
113+
expectType<string>(eset1.foo)
114+
expectType<number>(eset1.bar)
115+
})
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
{
2+
"name": "@vue/reactivity-transform",
3+
"version": "3.3.13",
4+
"description": "@vue/reactivity-transform",
5+
"main": "dist/reactivity-transform.cjs.js",
6+
"files": [
7+
"dist"
8+
],
9+
"buildOptions": {
10+
"formats": [
11+
"cjs"
12+
],
13+
"prod": false
14+
},
15+
"types": "dist/reactivity-transform.d.ts",
16+
"repository": {
17+
"type": "git",
18+
"url": "git+https://github.com/vuejs/core.git",
19+
"directory": "packages/reactivity-transform"
20+
},
21+
"keywords": [
22+
"vue"
23+
],
24+
"author": "Evan You",
25+
"license": "MIT",
26+
"bugs": {
27+
"url": "https://github.com/vuejs/core/issues"
28+
},
29+
"homepage": "https://github.com/vuejs/core/tree/dev/packages/reactivity-transform#readme",
30+
"dependencies": {
31+
"@babel/parser": "^7.23.5",
32+
"@vue/compiler-core": "workspace:*",
33+
"@vue/shared": "workspace:*",
34+
"estree-walker": "^2.0.2",
35+
"magic-string": "^0.30.5"
36+
},
37+
"devDependencies": {
38+
"@babel/core": "^7.23.5",
39+
"@babel/types": "^7.23.5"
40+
}
41+
}

packages/reactivity/src/ref.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -513,13 +513,14 @@ export type UnwrapRefSimple<T> = T extends
513513
| { [RawSymbol]?: true }
514514
? T
515515
: T extends Map<infer K, infer V>
516-
? Map<K, UnwrapRefSimple<V>>
516+
? Map<K, UnwrapRefSimple<V>> & UnwrapRef<Omit<T, keyof Map<any, any>>>
517517
: T extends WeakMap<infer K, infer V>
518-
? WeakMap<K, UnwrapRefSimple<V>>
518+
? WeakMap<K, UnwrapRefSimple<V>> &
519+
UnwrapRef<Omit<T, keyof WeakMap<any, any>>>
519520
: T extends Set<infer V>
520-
? Set<UnwrapRefSimple<V>>
521+
? Set<UnwrapRefSimple<V>> & UnwrapRef<Omit<T, keyof Set<any>>>
521522
: T extends WeakSet<infer V>
522-
? WeakSet<UnwrapRefSimple<V>>
523+
? WeakSet<UnwrapRefSimple<V>> & UnwrapRef<Omit<T, keyof WeakSet<any>>>
523524
: T extends ReadonlyArray<any>
524525
? { [K in keyof T]: UnwrapRefSimple<T[K]> }
525526
: T extends object & { [ShallowReactiveMarker]?: never }

packages/runtime-dom/__tests__/directives/vOn.spec.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,4 +135,32 @@ describe('runtime-dom: v-on directive', () => {
135135
handler(event, 'value', true)
136136
expect(fn).toBeCalledWith(event, 'value', true)
137137
})
138+
139+
it('withKeys cache wrapped listener separately for different modifiers', () => {
140+
const el1 = document.createElement('button')
141+
const el2 = document.createElement('button')
142+
const fn = vi.fn()
143+
const handler1 = withKeys(fn, ['a'])
144+
const handler2 = withKeys(fn, ['b'])
145+
expect(handler1 === handler2).toBe(false)
146+
patchEvent(el1, 'onKeyup', null, handler1, null)
147+
patchEvent(el2, 'onKeyup', null, handler2, null)
148+
triggerEvent(el1, 'keyup', e => (e.key = 'a'))
149+
triggerEvent(el2, 'keyup', e => (e.key = 'b'))
150+
expect(fn).toBeCalledTimes(2)
151+
})
152+
153+
it('withModifiers cache wrapped listener separately for different modifiers', () => {
154+
const el1 = document.createElement('button')
155+
const el2 = document.createElement('button')
156+
const fn = vi.fn()
157+
const handler1 = withModifiers(fn, ['ctrl'])
158+
const handler2 = withModifiers(fn, ['shift'])
159+
expect(handler1 === handler2).toBe(false)
160+
patchEvent(el1, 'onClick', null, handler1, null)
161+
patchEvent(el2, 'onClick', null, handler2, null)
162+
triggerEvent(el1, 'click', e => (e.ctrlKey = true))
163+
triggerEvent(el2, 'click', e => (e.shiftKey = true))
164+
expect(fn).toBeCalledTimes(2)
165+
})
138166
})

packages/runtime-dom/src/directives/vOn.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,14 @@ const modifierGuards: Record<
3535
export const withModifiers = <
3636
T extends (event: Event, ...args: unknown[]) => any
3737
>(
38-
fn: T & { _withMods?: T },
38+
fn: T & { _withMods?: { [key: string]: T } },
3939
modifiers: string[]
4040
) => {
41+
const cache = fn._withMods || (fn._withMods = {})
42+
const cacheKey = modifiers.join('.')
4143
return (
42-
fn._withMods ||
43-
(fn._withMods = ((event, ...args) => {
44+
cache[cacheKey] ||
45+
(cache[cacheKey] = ((event, ...args) => {
4446
for (let i = 0; i < modifiers.length; i++) {
4547
const guard = modifierGuards[modifiers[i]]
4648
if (guard && guard(event, modifiers)) return
@@ -66,7 +68,7 @@ const keyNames: Record<string, string | string[]> = {
6668
* @private
6769
*/
6870
export const withKeys = <T extends (event: KeyboardEvent) => any>(
69-
fn: T & { _withKeys?: T },
71+
fn: T & { _withKeys?: { [k: string]: T } },
7072
modifiers: string[]
7173
) => {
7274
let globalKeyCodes: LegacyConfig['keyCodes']
@@ -88,9 +90,12 @@ export const withKeys = <T extends (event: KeyboardEvent) => any>(
8890
}
8991
}
9092

93+
const cache: { [k: string]: T } = fn._withKeys || (fn._withKeys = {})
94+
const cacheKey = modifiers.join('.')
95+
9196
return (
92-
fn._withKeys ||
93-
(fn._withKeys = (event => {
97+
cache[cacheKey] ||
98+
(cache[cacheKey] = (event => {
9499
if (!('key' in event)) {
95100
return
96101
}

pnpm-lock.yaml

Lines changed: 25 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)