diff --git a/.github/contributing.md b/.github/contributing.md index fe2ac7c114b..5f3e4bf1938 100644 --- a/.github/contributing.md +++ b/.github/contributing.md @@ -36,9 +36,9 @@ Hi! I'm really excited that you are interested in contributing to Vue.js. Before - Make sure tests pass! -- Commit messages must follow the [commit message convention](./commit-convention.md) so that changelogs can be automatically generated. Commit messages are automatically validated before commit (by invoking [Git Hooks](https://git-scm.com/docs/githooks) via [yorkie](https://github.com/yyx990803/yorkie)). +- Commit messages must follow the [commit message convention](./commit-convention.md) so that changelogs can be automatically generated. Commit messages are automatically validated before commit (by invoking [Git Hooks](https://git-scm.com/docs/githooks) via [simple-git-hooks](https://github.com/toplenboren/simple-git-hooks)). -- No need to worry about code style as long as you have installed the dev dependencies - modified files are automatically formatted with Prettier on commit (by invoking [Git Hooks](https://git-scm.com/docs/githooks) via [yorkie](https://github.com/yyx990803/yorkie)). +- No need to worry about code style as long as you have installed the dev dependencies - modified files are automatically formatted with Prettier on commit (by invoking [Git Hooks](https://git-scm.com/docs/githooks) via [simple-git-hooks](https://github.com/toplenboren/simple-git-hooks)). ### Advanced Pull Request Tips @@ -267,8 +267,6 @@ Test coverage is continuously deployed at https://vue-next-coverage.netlify.app/ ### Testing Type Definition Correctness -This project uses [tsd](https://github.com/SamVerschueren/tsd) to test the built definition files (`*.d.ts`). - Type tests are located in the `test-dts` directory. To run the dts tests, run `nr test-dts`. Note that the type test requires all relevant `*.d.ts` files to be built first (and the script does it for you). Once the `d.ts` files are built and up-to-date, the tests can be re-run by simply running `nr test-dts`. ## Financial Contribution diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3128dd2cb4f..63fadbb2dcd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,15 +14,15 @@ jobs: unit-test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install pnpm uses: pnpm/action-setup@v2 - - name: Set node version to 16 - uses: actions/setup-node@v2 + - name: Set node version to 18 + uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 cache: 'pnpm' - run: pnpm install @@ -33,15 +33,15 @@ jobs: e2e-test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install pnpm uses: pnpm/action-setup@v2 - - name: Set node version to 16 - uses: actions/setup-node@v2 + - name: Set node version to 18 + uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 cache: 'pnpm' - run: pnpm install @@ -52,15 +52,15 @@ jobs: lint-and-test-dts: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install pnpm uses: pnpm/action-setup@v2 - - name: Set node version to 16 - uses: actions/setup-node@v2 + - name: Set node version to 18 + uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 cache: 'pnpm' - run: pnpm install @@ -68,6 +68,9 @@ jobs: - name: Run eslint run: pnpm run lint + # - name: Run prettier + # run: pnpm run format-check + - name: Run type declaration tests run: pnpm run test-dts @@ -76,15 +79,15 @@ jobs: env: CI_JOB_NUMBER: 1 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install pnpm uses: pnpm/action-setup@v2 - - name: Set node version to 16 - uses: actions/setup-node@v2 + - name: Set node version to 18 + uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 cache: 'pnpm' - run: pnpm install diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000000..1521c8b7652 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +dist diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fef732631a..634502a1cfb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,95 @@ +## [3.2.45](https://github.com/vuejs/core/compare/v3.2.44...v3.2.45) (2022-11-11) + + +### Bug Fixes + +* **compiler/v-model:** catch incorrect v-model usage on prop bindings ([001184e](https://github.com/vuejs/core/commit/001184e6bbbc85c4698f460b1f810beca3aed262)), closes [#5584](https://github.com/vuejs/core/issues/5584) +* **custom-elements:** also dispatch hyphenated version of emitted events ([#5378](https://github.com/vuejs/core/issues/5378)) ([0b39e46](https://github.com/vuejs/core/commit/0b39e46192c6258d5bf9d3b6992b84edb0b641d3)), closes [#5373](https://github.com/vuejs/core/issues/5373) +* **custom-elements:** custom element should re-instantiate when inserted again ([#6966](https://github.com/vuejs/core/issues/6966)) ([67890da](https://github.com/vuejs/core/commit/67890daad1a8474c5178565f32a4efa427db911a)), closes [#6934](https://github.com/vuejs/core/issues/6934) +* **custom-elements:** define declared properties in constructor ([#5328](https://github.com/vuejs/core/issues/5328)) ([55382ae](https://github.com/vuejs/core/commit/55382aed58aa3d937f442ad9445b3fff83a07de1)) +* **custom-elements:** ensure custom elements can inherit provides from ancestors ([#5098](https://github.com/vuejs/core/issues/5098)) ([192dcb6](https://github.com/vuejs/core/commit/192dcb648c0630ac20d2009eed512e142a72654a)), closes [#5096](https://github.com/vuejs/core/issues/5096) +* **custom-elements:** fix event emitting for async custom elements ([#5601](https://github.com/vuejs/core/issues/5601)) ([665f2ae](https://github.com/vuejs/core/commit/665f2ae121ec31d65cf22bd577f12fb1d9ffa4a2)), closes [#5599](https://github.com/vuejs/core/issues/5599) +* **custom-elements:** fix number type props casting check ([89f37ce](https://github.com/vuejs/core/commit/89f37ceb62363c77697d177675790a9ab81ba34f)), closes [#5793](https://github.com/vuejs/core/issues/5793) [#5794](https://github.com/vuejs/core/issues/5794) +* **custom-elements:** properties set pre-upgrade should not show up in $attrs ([afe8899](https://github.com/vuejs/core/commit/afe889999cbcaa11020c46c30b591a5ee6c3d4cf)) +* **custom-elements:** respect slot props in custom element mode ([ffef822](https://github.com/vuejs/core/commit/ffef8228694b39638f07c0fe5bc30d826262b672)) +* **custom-elements:** should not reflect non-decalred properties set before upgrade ([5e50909](https://github.com/vuejs/core/commit/5e509091000779acbfae4c85cc1cc3973b1b2e64)) +* **hmr/keep-alive:** fix error in reload component ([#7049](https://github.com/vuejs/core/issues/7049)) ([a54bff2](https://github.com/vuejs/core/commit/a54bff2c9c8e1d908b4a0f3826ac715c9a35e68c)), closes [#7042](https://github.com/vuejs/core/issues/7042) +* **runtime-core:** fix move/removal of static fragments containing text nodes ([#6858](https://github.com/vuejs/core/issues/6858)) ([4049ffc](https://github.com/vuejs/core/commit/4049ffcf29dc12dca71f682edf0b422a5c502e23)), closes [#6852](https://github.com/vuejs/core/issues/6852) +* **sfc:** also generate getter for import bindings during dev ([0594400](https://github.com/vuejs/core/commit/0594400980d3bdc394e92db63fc939a6609f7a94)) +* **sfc:** ensure ` `) - expect(content).toMatch('return { aa, bb, cc, dd, a, b, c, d, xx, x }') + expect(content).toMatch( + `return { get aa() { return aa }, set aa(v) { aa = v }, ` + + `bb, cc, dd, get a() { return a }, set a(v) { a = v }, b, c, d, ` + + `get xx() { return xx }, get x() { return x } }` + ) expect(bindings).toStrictEqual({ x: BindingTypes.SETUP_MAYBE_REF, a: BindingTypes.SETUP_LET, @@ -141,6 +145,21 @@ const myEmit = defineEmits(['foo', 'bar']) expect(content).toMatch(`emits: ['a'],`) }) + // #6757 + test('defineProps/defineEmits in multi-variable declaration fix #6757 ', () => { + const { content } = compile(` + + `) + assertCode(content) + expect(content).toMatch(`const a = 1;`) // test correct removal + expect(content).toMatch(`props: ['item'],`) + expect(content).toMatch(`emits: ['a'],`) + }) + test('defineProps/defineEmits in multi-variable declaration (full removal)', () => { const { content } = compile(` + `) + expect(bindings).toStrictEqual({ + ref: BindingTypes.SETUP_MAYBE_REF, + reactive: BindingTypes.SETUP_MAYBE_REF, + foo: BindingTypes.SETUP_MAYBE_REF, + bar: BindingTypes.SETUP_MAYBE_REF + }) + }) + + test('import w/ alias', () => { + const { bindings } = compile(` + + `) + expect(bindings).toStrictEqual({ + _reactive: BindingTypes.SETUP_MAYBE_REF, + _ref: BindingTypes.SETUP_MAYBE_REF, + foo: BindingTypes.SETUP_MAYBE_REF, + bar: BindingTypes.SETUP_MAYBE_REF + }) + }) + + test('aliased usage before import site', () => { + const { bindings } = compile(` + + `) + expect(bindings).toStrictEqual({ + bar: BindingTypes.SETUP_REACTIVE_CONST, + x: BindingTypes.SETUP_CONST + }) + }) + }) }) // in dev mode, declared bindings are returned as an object from setup() @@ -365,7 +433,10 @@ defineExpose({ foo: 123 }) // FooBaz: used as PascalCase component // FooQux: used as kebab-case component // foo: lowercase component - expect(content).toMatch(`return { fooBar, FooBaz, FooQux, foo }`) + expect(content).toMatch( + `return { fooBar, get FooBaz() { return FooBaz }, ` + + `get FooQux() { return FooQux }, get foo() { return foo } }` + ) assertCode(content) }) @@ -378,7 +449,7 @@ defineExpose({ foo: 123 })
`) - expect(content).toMatch(`return { vMyDir }`) + expect(content).toMatch(`return { get vMyDir() { return vMyDir } }`) assertCode(content) }) @@ -393,7 +464,9 @@ defineExpose({ foo: 123 })
`) - expect(content).toMatch(`return { cond, bar, baz }`) + expect(content).toMatch( + `return { cond, get bar() { return bar }, get baz() { return baz } }` + ) assertCode(content) }) @@ -409,7 +482,9 @@ defineExpose({ foo: 123 }) // x: used in interpolation // y: should not be matched by {{ yy }} or 'y' in binding exps // x$y: #4274 should escape special chars when creating Regex - expect(content).toMatch(`return { x, z, x$y }`) + expect(content).toMatch( + `return { get x() { return x }, get z() { return z }, get x$y() { return x$y } }` + ) assertCode(content) }) @@ -424,7 +499,9 @@ defineExpose({ foo: 123 }) `) // VAR2 should not be matched - expect(content).toMatch(`return { VAR, VAR3 }`) + expect(content).toMatch( + `return { get VAR() { return VAR }, get VAR3() { return VAR3 } }` + ) assertCode(content) }) @@ -439,7 +516,9 @@ defineExpose({ foo: 123 }) `) - expect(content).toMatch(`return { FooBaz, Last }`) + expect(content).toMatch( + `return { get FooBaz() { return FooBaz }, get Last() { return Last } }` + ) assertCode(content) }) @@ -458,7 +537,7 @@ defineExpose({ foo: 123 })
`) - expect(content).toMatch(`return { a, b, Baz }`) + expect(content).toMatch(`return { a, b, get Baz() { return Baz } }`) assertCode(content) }) @@ -609,6 +688,26 @@ defineExpose({ foo: 123 }) assertCode(content) }) + test('v-model should not generate ref assignment code for non-setup bindings', () => { + const { content } = compile( + ` + + + `, + { inlineTemplate: true } + ) + expect(content).not.toMatch(`_isRef(foo)`) + }) + test('template assignment expression codegen', () => { const { content } = compile( ` + + `) + 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('defineProps w/ exported interface', () => { const { content, bindings } = compile(` `) @@ -967,7 +1097,16 @@ const emit = defineEmits(['a', 'b']) `qux: { type: Function, required: false, default() { return 1 } }` ) expect(content).toMatch( - `{ foo: string, bar?: number, baz: boolean, qux(): number }` + `quux: { type: Function, required: false, default() { } }` + ) + expect(content).toMatch( + `quuxx: { type: Promise, required: false, async default() { return await Promise.resolve('hi') } }` + ) + expect(content).toMatch( + `fred: { type: String, required: false, get default() { return 'fred' } }` + ) + expect(content).toMatch( + `{ foo: string, bar?: number, baz: boolean, qux(): number, quux(): void, quuxx: Promise, fred: string }` ) expect(content).toMatch(`const props = __props`) expect(bindings).toStrictEqual({ @@ -975,6 +1114,9 @@ const emit = defineEmits(['a', 'b']) bar: BindingTypes.PROPS, baz: BindingTypes.PROPS, qux: BindingTypes.PROPS, + quux: BindingTypes.PROPS, + quuxx: BindingTypes.PROPS, + fred: BindingTypes.PROPS, props: BindingTypes.SETUP_CONST }) }) @@ -1108,6 +1250,19 @@ const emit = defineEmits(['a', 'b']) expect(content).toMatch(`emits: ["foo", "bar"]`) }) + // #5393 + test('defineEmits w/ type (interface ts type)', () => { + const { content } = compile(` + + `) + assertCode(content) + expect(content).toMatch(`setup(__props, { expose, emit }) {`) + expect(content).toMatch(`emits: ['foo']`) + }) + test('runtime Enum', () => { const { content, bindings } = compile( `` ) - expect(content).toMatch(`return { Baz }`) + expect(content).toMatch(`return { get Baz() { return Baz } }`) assertCode(content) }) }) diff --git a/packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts b/packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts index 25fb4bed280..7d35f91abf2 100644 --- a/packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts @@ -184,6 +184,24 @@ describe('sfc props transform', () => { assertCode(content) }) + // #6960 + test('computed static key', () => { + const { content, bindings } = compile(` + + + `) + expect(content).not.toMatch(`const { foo } =`) + expect(content).toMatch(`console.log(__props.foo)`) + expect(content).toMatch(`_toDisplayString(__props.foo)`) + assertCode(content) + expect(bindings).toStrictEqual({ + foo: BindingTypes.PROPS + }) + }) + describe('errors', () => { test('should error on deep destructure', () => { expect(() => diff --git a/packages/compiler-sfc/__tests__/compileScriptRefTransform.spec.ts b/packages/compiler-sfc/__tests__/compileScriptRefTransform.spec.ts index 88d62f2b478..8ae5275661e 100644 --- a/packages/compiler-sfc/__tests__/compileScriptRefTransform.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScriptRefTransform.spec.ts @@ -32,7 +32,10 @@ describe('sfc ref transform', () => { // normal declarations left untouched expect(content).toMatch(`let c = () => {}`) expect(content).toMatch(`let d`) - expect(content).toMatch(`return { foo, a, b, c, d, ref, shallowRef }`) + expect(content).toMatch( + `return { foo, a, b, get c() { return c }, set c(v) { c = v }, ` + + `get d() { return d }, set d(v) { d = v }, ref, shallowRef }` + ) assertCode(content) expect(bindings).toStrictEqual({ foo: BindingTypes.SETUP_REF, diff --git a/packages/compiler-sfc/__tests__/compileTemplate.spec.ts b/packages/compiler-sfc/__tests__/compileTemplate.spec.ts index f58b6338de9..b471b67c9ca 100644 --- a/packages/compiler-sfc/__tests__/compileTemplate.spec.ts +++ b/packages/compiler-sfc/__tests__/compileTemplate.spec.ts @@ -22,6 +22,22 @@ test('should work', () => { expect(result.code).toMatch(`export function render(`) }) +// #6807 +test('should work with style comment', () => { + const source = ` +
{{ render }}
+ ` + + const result = compile({ filename: 'example.vue', source }) + expect(result.errors.length).toBe(0) + expect(result.source).toBe(source) + expect(result.code).toMatch(`{"width":"300px","height":"100px"}`) +}) + test('preprocess pug', () => { const template = parse( ` diff --git a/packages/compiler-sfc/__tests__/cssVars.spec.ts b/packages/compiler-sfc/__tests__/cssVars.spec.ts index 9d3df069e76..ffa5d4e798b 100644 --- a/packages/compiler-sfc/__tests__/cssVars.spec.ts +++ b/packages/compiler-sfc/__tests__/cssVars.spec.ts @@ -12,7 +12,7 @@ describe('CSS vars injection', () => { ) expect(content).toMatch(`_useCssVars(_ctx => ({ "${mockId}-color": (_ctx.color), - "${mockId}-font_size": (_ctx.font.size) + "${mockId}-font\\.size": (_ctx.font.size) })`) assertCode(content) }) @@ -79,6 +79,10 @@ describe('CSS vars injection', () => { source: `.foo { color: v-bind(color); font-size: v-bind('font.size'); + + font-weight: v-bind(_φ); + font-size: v-bind(1-字号); + font-family: v-bind(フォント); }`, filename: 'test.css', id: 'data-v-test' @@ -86,7 +90,11 @@ describe('CSS vars injection', () => { expect(code).toMatchInlineSnapshot(` ".foo { color: var(--test-color); - font-size: var(--test-font_size); + font-size: var(--test-font\\\\.size); + + font-weight: var(--test-_φ); + font-size: var(--test-1-字号); + font-family: var(--test-フォント); }" `) }) @@ -225,10 +233,10 @@ describe('CSS vars injection', () => { ) expect(content).toMatch(`_useCssVars(_ctx => ({ "${mockId}-foo": (_unref(foo)), - "${mockId}-foo____px_": (_unref(foo) + 'px'), - "${mockId}-_a___b____2____px_": ((_unref(a) + _unref(b)) / 2 + 'px'), - "${mockId}-__a___b______2___a_": (((_unref(a) + _unref(b))) / (2 * _unref(a))) -})`) + "${mockId}-foo\\ \\+\\ \\'px\\'": (_unref(foo) + 'px'), + "${mockId}-\\(a\\ \\+\\ b\\)\\ \\/\\ 2\\ \\+\\ \\'px\\'": ((_unref(a) + _unref(b)) / 2 + 'px'), + "${mockId}-\\(\\(a\\ \\+\\ b\\)\\)\\ \\/\\ \\(2\\ \\*\\ a\\)": (((_unref(a) + _unref(b))) / (2 * _unref(a))) +}))`) assertCode(content) }) diff --git a/packages/compiler-sfc/__tests__/parse.spec.ts b/packages/compiler-sfc/__tests__/parse.spec.ts index 9db9bb7f3e6..5f1db5e2499 100644 --- a/packages/compiler-sfc/__tests__/parse.spec.ts +++ b/packages/compiler-sfc/__tests__/parse.spec.ts @@ -268,7 +268,9 @@ h1 { color: red } }) test('treat custom blocks as raw text', () => { - const { errors, descriptor } = parse(` <-& `) + const { errors, descriptor } = parse( + ` <-& ` + ) expect(errors.length).toBe(0) expect(descriptor.customBlocks[0].content).toBe(` <-& `) }) @@ -309,5 +311,13 @@ h1 { color: red } ).errors.length ).toBe(0) }) + + // # 6676 + test('should throw error if no