Răsfoiți Sursa

Merge branch 'main' into edison/fix/vModel

edison 1 an în urmă
părinte
comite
fb02ff066a

+ 12 - 12
package.json

@@ -1,7 +1,7 @@
 {
   "private": true,
   "version": "3.5.12",
-  "packageManager": "pnpm@9.12.0",
+  "packageManager": "pnpm@9.12.2",
   "type": "module",
   "scripts": {
     "dev": "node scripts/dev.js",
@@ -62,13 +62,13 @@
     "@babel/parser": "catalog:",
     "@babel/types": "catalog:",
     "@rollup/plugin-alias": "^5.1.1",
-    "@rollup/plugin-commonjs": "^28.0.0",
+    "@rollup/plugin-commonjs": "^28.0.1",
     "@rollup/plugin-json": "^6.1.0",
     "@rollup/plugin-node-resolve": "^15.3.0",
     "@rollup/plugin-replace": "5.0.4",
-    "@swc/core": "^1.7.28",
+    "@swc/core": "^1.7.36",
     "@types/hash-sum": "^1.0.2",
-    "@types/node": "^20.16.10",
+    "@types/node": "^20.16.13",
     "@types/semver": "^7.5.8",
     "@types/serve-handler": "^6.1.4",
     "@vitest/coverage-v8": "^2.1.1",
@@ -77,18 +77,18 @@
     "enquirer": "^2.4.1",
     "esbuild": "^0.24.0",
     "esbuild-plugin-polyfill-node": "^0.3.0",
-    "eslint": "^9.12.0",
+    "eslint": "^9.13.0",
     "eslint-plugin-import-x": "^4.3.1",
     "@vitest/eslint-plugin": "^1.0.1",
     "estree-walker": "catalog:",
     "jsdom": "^25.0.0",
     "lint-staged": "^15.2.10",
     "lodash": "^4.17.21",
-    "magic-string": "^0.30.11",
+    "magic-string": "^0.30.12",
     "markdown-table": "^3.0.3",
     "marked": "13.0.3",
-    "npm-run-all2": "^6.2.3",
-    "picocolors": "^1.1.0",
+    "npm-run-all2": "^6.2.6",
+    "picocolors": "^1.1.1",
     "prettier": "^3.3.3",
     "pretty-bytes": "^6.1.1",
     "pug": "^3.0.3",
@@ -99,13 +99,13 @@
     "rollup-plugin-esbuild": "^6.1.1",
     "rollup-plugin-polyfill-node": "^0.13.0",
     "semver": "^7.6.3",
-    "serve": "^14.2.3",
-    "serve-handler": "^6.1.5",
+    "serve": "^14.2.4",
+    "serve-handler": "^6.1.6",
     "simple-git-hooks": "^2.11.1",
     "todomvc-app-css": "^2.4.3",
-    "tslib": "^2.7.0",
+    "tslib": "^2.8.0",
     "typescript": "~5.6.2",
-    "typescript-eslint": "^8.8.0",
+    "typescript-eslint": "^8.10.0",
     "vite": "catalog:",
     "vitest": "^2.1.1"
   },

+ 1 - 1
packages-private/sfc-playground/src/download/template/package.json

@@ -12,6 +12,6 @@
   },
   "devDependencies": {
     "@vitejs/plugin-vue": "^5.1.4",
-    "vite": "^5.4.8"
+    "vite": "^5.4.9"
   }
 }

+ 52 - 0
packages/compiler-sfc/__tests__/compileScript/__snapshots__/defineProps.spec.ts.snap

@@ -233,6 +233,33 @@ export default /*@__PURE__*/_defineComponent({
 
       
     
+return {  }
+}
+
+})"
+`;
+
+exports[`defineProps > w/ extends intersection type 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+type Foo = {
+        x?: number;
+      };
+      interface Props extends Foo {
+        z: number
+        y: string
+      }
+      
+export default /*@__PURE__*/_defineComponent({
+  props: {
+    z: { type: Number, required: true },
+    y: { type: String, required: true },
+    x: { type: Number, required: false }
+  },
+  setup(__props: any, { expose: __expose }) {
+  __expose();
+
+      
+    
 return {  }
 }
 
@@ -268,6 +295,31 @@ export default /*@__PURE__*/_defineComponent({
 
     
     
+return {  }
+}
+
+})"
+`;
+
+exports[`defineProps > w/ intersection type 1`] = `
+"import { defineComponent as _defineComponent } from 'vue'
+type Foo = {
+        x?: number;
+      };
+      type Bar = {
+        y: string;
+      };
+      
+export default /*@__PURE__*/_defineComponent({
+  props: {
+    x: { type: Number, required: false },
+    y: { type: String, required: true }
+  },
+  setup(__props: any, { expose: __expose }) {
+  __expose();
+
+      
+    
 return {  }
 }
 

+ 45 - 0
packages/compiler-sfc/__tests__/compileScript/defineProps.spec.ts

@@ -261,6 +261,51 @@ const props = defineProps({ foo: String })
     })
   })
 
+  test('w/ extends intersection type', () => {
+    const { content, bindings } = compile(`
+    <script setup lang="ts">
+      type Foo = {
+        x?: number;
+      };
+      interface Props extends Foo {
+        z: number
+        y: string
+      }
+      defineProps<Props>()
+    </script>
+    `)
+    assertCode(content)
+    expect(content).toMatch(`z: { type: Number, required: true }`)
+    expect(content).toMatch(`y: { type: String, required: true }`)
+    expect(content).toMatch(`x: { type: Number, required: false }`)
+    expect(bindings).toStrictEqual({
+      x: BindingTypes.PROPS,
+      y: BindingTypes.PROPS,
+      z: BindingTypes.PROPS,
+    })
+  })
+
+  test('w/ intersection type', () => {
+    const { content, bindings } = compile(`
+    <script setup lang="ts">
+      type Foo = {
+        x?: number;
+      };
+      type Bar = {
+        y: string;
+      };
+      defineProps<Foo & Bar>()
+    </script>
+    `)
+    assertCode(content)
+    expect(content).toMatch(`y: { type: String, required: true }`)
+    expect(content).toMatch(`x: { type: Number, required: false }`)
+    expect(bindings).toStrictEqual({
+      x: BindingTypes.PROPS,
+      y: BindingTypes.PROPS,
+    })
+  })
+
   test('w/ exported interface', () => {
     const { content, bindings } = compile(`
     <script setup lang="ts">

+ 1 - 1
packages/compiler-sfc/package.json

@@ -62,6 +62,6 @@
     "postcss-modules": "^6.0.0",
     "postcss-selector-parser": "^6.1.2",
     "pug": "^3.0.3",
-    "sass": "^1.79.4"
+    "sass": "^1.80.3"
   }
 }

+ 21 - 0
packages/runtime-core/__tests__/rendererAttrsFallthrough.spec.ts

@@ -6,6 +6,7 @@
 import {
   Fragment,
   type FunctionalComponent,
+  Teleport,
   createBlock,
   createCommentVNode,
   createElementBlock,
@@ -391,6 +392,26 @@ describe('attribute fallthrough', () => {
     expect(`Extraneous non-emits event listeners`).toHaveBeenWarned()
   })
 
+  it('should warn when fallthrough fails on teleport root node', () => {
+    const Parent = {
+      render() {
+        return h(Child, { class: 'parent' })
+      },
+    }
+    const root = document.createElement('div')
+
+    const Child = defineComponent({
+      render() {
+        return h(Teleport, { to: root }, h('div'))
+      },
+    })
+
+    document.body.appendChild(root)
+    render(h(Parent), root)
+
+    expect(`Extraneous non-props attributes (class)`).toHaveBeenWarned()
+  })
+
   it('should dedupe same listeners when $attrs is used during render', () => {
     const click = vi.fn()
     const count = ref(0)

+ 1 - 1
packages/runtime-core/src/component.ts

@@ -1006,7 +1006,7 @@ export function finishComponentSetup(
           instance.vnode.props &&
           instance.vnode.props['inline-template']) ||
         Component.template ||
-        resolveMergedOptions(instance).template
+        (__FEATURE_OPTIONS_API__ && resolveMergedOptions(instance).template)
       if (template) {
         if (__DEV__) {
           startMeasure(instance, `compile`)

+ 1 - 1
packages/runtime-core/src/componentRenderUtils.ts

@@ -190,7 +190,7 @@ export function renderComponentRoot(
             `Extraneous non-props attributes (` +
               `${extraAttrs.join(', ')}) ` +
               `were passed to component but could not be automatically inherited ` +
-              `because component renders fragment or text root nodes.`,
+              `because component renders fragment or text or teleport root nodes.`,
           )
         }
         if (eventAttrs.length) {

+ 141 - 1
packages/shared/__tests__/normalizeProp.spec.ts

@@ -1,4 +1,10 @@
-import { normalizeClass, parseStringStyle } from '../src'
+import {
+  normalizeClass,
+  normalizeProps,
+  normalizeStyle,
+  parseStringStyle,
+  stringifyStyle,
+} from '../src'
 
 describe('normalizeClass', () => {
   test('handles undefined correctly', () => {
@@ -15,6 +21,11 @@ describe('normalizeClass', () => {
     )
   })
 
+  test('handles string containing spaces correctly', () => {
+    expect(normalizeClass('foo1 ')).toEqual('foo1')
+    expect(normalizeClass(['foo ', ' baz '])).toEqual('foo baz')
+  })
+
   test('handles empty array correctly', () => {
     expect(normalizeClass([])).toEqual('')
   })
@@ -92,3 +103,132 @@ describe('normalizeClass', () => {
     `)
   })
 })
+
+describe('normalizeStyle', () => {
+  test('handles string correctly', () => {
+    expect(normalizeStyle('foo')).toEqual('foo')
+  })
+
+  test('handles array correctly', () => {
+    const style: any = normalizeStyle([
+      `border: 1px solid transparent;
+    background: linear-gradient(white, white) padding-box,
+      repeating-linear-gradient(
+        -45deg,
+        #ccc 0,
+        #ccc 0.5em,
+        white 0,
+        white 0.75em
+      );`,
+    ])
+
+    expect(style.border).toEqual('1px solid transparent')
+
+    expect(style.background).toEqual(`linear-gradient(white, white) padding-box,
+      repeating-linear-gradient(
+        -45deg,
+        #ccc 0,
+        #ccc 0.5em,
+        white 0,
+        white 0.75em
+      )`)
+  })
+
+  test('handles object correctly', () => {
+    const styleObj = {
+      border: '1px solid transparent',
+      background: `linear-gradient(white, white) padding-box,
+      repeating-linear-gradient(
+        -45deg,
+        #ccc 0,
+        #ccc 0.5em,
+        white 0,
+        white 0.75em
+      )`,
+    }
+    const style: any = normalizeStyle(styleObj)
+    expect(style.border).toEqual(styleObj.border)
+    expect(style.background).toEqual(styleObj.background)
+  })
+})
+
+describe('stringifyStyle', () => {
+  test('should return empty string for undefined or string styles', () => {
+    expect(stringifyStyle(undefined)).toBe('')
+    expect(stringifyStyle('')).toBe('')
+    expect(stringifyStyle('color: blue;')).toBe('')
+  })
+
+  test('should return valid CSS string for normalized style object', () => {
+    const style = {
+      color: 'blue',
+      fontSize: '14px',
+      backgroundColor: 'white',
+      opacity: 0.8,
+      margin: 0,
+      '--custom-color': 'red',
+    }
+
+    expect(stringifyStyle(style)).toBe(
+      'color:blue;font-size:14px;background-color:white;opacity:0.8;margin:0;--custom-color:red;',
+    )
+  })
+
+  test('should ignore non-string or non-number values in style object', () => {
+    const style: any = {
+      color: 'blue',
+      fontSize: '14px',
+      lineHeight: true,
+      padding: null,
+      margin: undefined,
+    }
+
+    const expected = 'color:blue;font-size:14px;'
+    expect(stringifyStyle(style)).toBe(expected)
+  })
+})
+
+describe('normalizeProps', () => {
+  test('should return null when props is null', () => {
+    const props = null
+    const result = normalizeProps(props)
+    expect(result).toBeNull()
+  })
+
+  test('should normalize class prop when it is an array', () => {
+    const props = {
+      class: ['class1', 'class2'],
+    }
+    const result = normalizeProps(props)
+    expect(result).toEqual({
+      class: 'class1 class2',
+    })
+  })
+
+  test('should normalize class prop when it is an object', () => {
+    const props = {
+      class: {
+        class1: true,
+        class2: false,
+        class3: true,
+      },
+    }
+    const result = normalizeProps(props)
+    expect(result).toEqual({
+      class: 'class1 class3',
+    })
+  })
+
+  test('should normalize style prop', () => {
+    const props = {
+      style: ['color: blue', 'font-size: 14px'],
+    }
+    const result = normalizeProps(props)
+    expect(result).toEqual({
+      style: {
+        color: 'blue',
+        'font-size': '14px',
+      },
+    })
+  })
+})

+ 1 - 1
packages/vue/README.md

@@ -25,7 +25,7 @@
   - For use with bundlers like `webpack`, `rollup` and `parcel`.
   - Leaves prod/dev branches with `process.env.NODE_ENV` guards (must be replaced by bundler)
   - Does not ship minified builds (to be done together with the rest of the code after bundling)
-  - Imports dependencies (e.g. `@vue/runtime-core`, `@vue/runtime-compiler`)
+  - Imports dependencies (e.g. `@vue/runtime-core`, `@vue/compiler-core`)
     - Imported dependencies are also `esm-bundler` builds and will in turn import their dependencies (e.g. `@vue/runtime-core` imports `@vue/reactivity`)
     - This means you **can** install/import these deps individually without ending up with different instances of these dependencies, but you must make sure they all resolve to the same version.
   - In-browser template compilation:

Fișier diff suprimat deoarece este prea mare
+ 326 - 180
pnpm-lock.yaml


Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff