Преглед изворни кода

chore: Merge branch 'main' into minor

Evan You пре 2 година
родитељ
комит
95f6fffea2

+ 11 - 0
CHANGELOG.md

@@ -1,3 +1,14 @@
+## [3.3.13](https://github.com/vuejs/core/compare/v3.3.12...v3.3.13) (2023-12-19)
+
+
+### Bug Fixes
+
+* **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)
+* **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)
+* **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)
+
+
+
 # [3.4.0-beta.3](https://github.com/vuejs/core/compare/v3.3.12...v3.4.0-beta.3) (2023-12-16)
 
 

+ 4 - 0
packages/compiler-core/__tests__/utils.spec.ts

@@ -95,6 +95,10 @@ describe('isMemberExpression', () => {
     expect(fn(`123[a]`)).toBe(true)
     expect(fn(`foo() as string`)).toBe(false)
     expect(fn(`a + b as string`)).toBe(false)
+    // #9865
+    expect(fn('""')).toBe(false)
+    expect(fn('undefined')).toBe(false)
+    expect(fn('null')).toBe(false)
   })
 })
 

+ 1 - 1
packages/compiler-core/src/utils.ts

@@ -163,7 +163,7 @@ export const isMemberExpressionNode = __BROWSER__
         return (
           ret.type === 'MemberExpression' ||
           ret.type === 'OptionalMemberExpression' ||
-          ret.type === 'Identifier'
+          (ret.type === 'Identifier' && ret.name !== 'undefined')
         )
       } catch (e) {
         return false

+ 23 - 0
packages/dts-test/reactivity.test-d.ts

@@ -77,6 +77,18 @@ describe('should unwrap Map correctly', () => {
   expectType<number>(wm2.get({})!.wrap)
 })
 
+describe('should unwrap extended Map correctly', () => {
+  class ExtendendMap1 extends Map<string, { wrap: Ref<number> }> {
+    foo = ref('foo')
+    bar = 1
+  }
+
+  const emap1 = reactive(new ExtendendMap1())
+  expectType<string>(emap1.foo)
+  expectType<number>(emap1.bar)
+  expectType<number>(emap1.get('a')!.wrap)
+})
+
 describe('should unwrap Set correctly', () => {
   const set = reactive(new Set<Ref<number>>())
   expectType<Set<Ref<number>>>(set)
@@ -90,3 +102,14 @@ describe('should unwrap Set correctly', () => {
   const ws2 = reactive(new WeakSet<{ wrap: Ref<number> }>())
   expectType<WeakSet<{ wrap: number }>>(ws2)
 })
+
+describe('should unwrap extended Set correctly', () => {
+  class ExtendendSet1 extends Set<{ wrap: Ref<number> }> {
+    foo = ref('foo')
+    bar = 1
+  }
+
+  const eset1 = reactive(new ExtendendSet1())
+  expectType<string>(eset1.foo)
+  expectType<number>(eset1.bar)
+})

+ 41 - 0
packages/reactivity-transform/package.json

@@ -0,0 +1,41 @@
+{
+  "name": "@vue/reactivity-transform",
+  "version": "3.3.13",
+  "description": "@vue/reactivity-transform",
+  "main": "dist/reactivity-transform.cjs.js",
+  "files": [
+    "dist"
+  ],
+  "buildOptions": {
+    "formats": [
+      "cjs"
+    ],
+    "prod": false
+  },
+  "types": "dist/reactivity-transform.d.ts",
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/vuejs/core.git",
+    "directory": "packages/reactivity-transform"
+  },
+  "keywords": [
+    "vue"
+  ],
+  "author": "Evan You",
+  "license": "MIT",
+  "bugs": {
+    "url": "https://github.com/vuejs/core/issues"
+  },
+  "homepage": "https://github.com/vuejs/core/tree/dev/packages/reactivity-transform#readme",
+  "dependencies": {
+    "@babel/parser": "^7.23.5",
+    "@vue/compiler-core": "workspace:*",
+    "@vue/shared": "workspace:*",
+    "estree-walker": "^2.0.2",
+    "magic-string": "^0.30.5"
+  },
+  "devDependencies": {
+    "@babel/core": "^7.23.5",
+    "@babel/types": "^7.23.5"
+  }
+}

+ 5 - 4
packages/reactivity/src/ref.ts

@@ -513,13 +513,14 @@ export type UnwrapRefSimple<T> = T extends
   | { [RawSymbol]?: true }
   ? T
   : T extends Map<infer K, infer V>
-    ? Map<K, UnwrapRefSimple<V>>
+    ? Map<K, UnwrapRefSimple<V>> & UnwrapRef<Omit<T, keyof Map<any, any>>>
     : T extends WeakMap<infer K, infer V>
-      ? WeakMap<K, UnwrapRefSimple<V>>
+      ? WeakMap<K, UnwrapRefSimple<V>> &
+          UnwrapRef<Omit<T, keyof WeakMap<any, any>>>
       : T extends Set<infer V>
-        ? Set<UnwrapRefSimple<V>>
+        ? Set<UnwrapRefSimple<V>> & UnwrapRef<Omit<T, keyof Set<any>>>
         : T extends WeakSet<infer V>
-          ? WeakSet<UnwrapRefSimple<V>>
+          ? WeakSet<UnwrapRefSimple<V>> & UnwrapRef<Omit<T, keyof WeakSet<any>>>
           : T extends ReadonlyArray<any>
             ? { [K in keyof T]: UnwrapRefSimple<T[K]> }
             : T extends object & { [ShallowReactiveMarker]?: never }

+ 28 - 0
packages/runtime-dom/__tests__/directives/vOn.spec.ts

@@ -135,4 +135,32 @@ describe('runtime-dom: v-on directive', () => {
     handler(event, 'value', true)
     expect(fn).toBeCalledWith(event, 'value', true)
   })
+
+  it('withKeys cache wrapped listener separately for different modifiers', () => {
+    const el1 = document.createElement('button')
+    const el2 = document.createElement('button')
+    const fn = vi.fn()
+    const handler1 = withKeys(fn, ['a'])
+    const handler2 = withKeys(fn, ['b'])
+    expect(handler1 === handler2).toBe(false)
+    patchEvent(el1, 'onKeyup', null, handler1, null)
+    patchEvent(el2, 'onKeyup', null, handler2, null)
+    triggerEvent(el1, 'keyup', e => (e.key = 'a'))
+    triggerEvent(el2, 'keyup', e => (e.key = 'b'))
+    expect(fn).toBeCalledTimes(2)
+  })
+
+  it('withModifiers cache wrapped listener separately for different modifiers', () => {
+    const el1 = document.createElement('button')
+    const el2 = document.createElement('button')
+    const fn = vi.fn()
+    const handler1 = withModifiers(fn, ['ctrl'])
+    const handler2 = withModifiers(fn, ['shift'])
+    expect(handler1 === handler2).toBe(false)
+    patchEvent(el1, 'onClick', null, handler1, null)
+    patchEvent(el2, 'onClick', null, handler2, null)
+    triggerEvent(el1, 'click', e => (e.ctrlKey = true))
+    triggerEvent(el2, 'click', e => (e.shiftKey = true))
+    expect(fn).toBeCalledTimes(2)
+  })
 })

+ 11 - 6
packages/runtime-dom/src/directives/vOn.ts

@@ -35,12 +35,14 @@ const modifierGuards: Record<
 export const withModifiers = <
   T extends (event: Event, ...args: unknown[]) => any
 >(
-  fn: T & { _withMods?: T },
+  fn: T & { _withMods?: { [key: string]: T } },
   modifiers: string[]
 ) => {
+  const cache = fn._withMods || (fn._withMods = {})
+  const cacheKey = modifiers.join('.')
   return (
-    fn._withMods ||
-    (fn._withMods = ((event, ...args) => {
+    cache[cacheKey] ||
+    (cache[cacheKey] = ((event, ...args) => {
       for (let i = 0; i < modifiers.length; i++) {
         const guard = modifierGuards[modifiers[i]]
         if (guard && guard(event, modifiers)) return
@@ -66,7 +68,7 @@ const keyNames: Record<string, string | string[]> = {
  * @private
  */
 export const withKeys = <T extends (event: KeyboardEvent) => any>(
-  fn: T & { _withKeys?: T },
+  fn: T & { _withKeys?: { [k: string]: T } },
   modifiers: string[]
 ) => {
   let globalKeyCodes: LegacyConfig['keyCodes']
@@ -88,9 +90,12 @@ export const withKeys = <T extends (event: KeyboardEvent) => any>(
     }
   }
 
+  const cache: { [k: string]: T } = fn._withKeys || (fn._withKeys = {})
+  const cacheKey = modifiers.join('.')
+
   return (
-    fn._withKeys ||
-    (fn._withKeys = (event => {
+    cache[cacheKey] ||
+    (cache[cacheKey] = (event => {
       if (!('key' in event)) {
         return
       }

+ 25 - 0
pnpm-lock.yaml

@@ -296,6 +296,31 @@ importers:
         specifier: workspace:*
         version: link:../shared
 
+  packages/reactivity-transform:
+    dependencies:
+      '@babel/parser':
+        specifier: ^7.23.5
+        version: 7.23.5
+      '@vue/compiler-core':
+        specifier: workspace:*
+        version: link:../compiler-core
+      '@vue/shared':
+        specifier: workspace:*
+        version: link:../shared
+      estree-walker:
+        specifier: ^2.0.2
+        version: 2.0.2
+      magic-string:
+        specifier: ^0.30.5
+        version: 0.30.5
+    devDependencies:
+      '@babel/core':
+        specifier: ^7.23.5
+        version: 7.23.5
+      '@babel/types':
+        specifier: ^7.23.5
+        version: 7.23.5
+
   packages/runtime-core:
     dependencies:
       '@vue/reactivity':