diff --git a/.eslintrc.js b/.eslintrc.js index cdbb1dffd91..c0282ebd817 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -6,7 +6,7 @@ module.exports = { parserOptions: { sourceType: 'module' }, - plugins: ["jest"], + plugins: ['jest'], rules: { 'no-debugger': 'error', 'no-unused-vars': [ @@ -72,7 +72,12 @@ module.exports = { }, // Node scripts { - files: ['scripts/**', './*.js', 'packages/**/index.js', 'packages/size-check/**'], + files: [ + 'scripts/**', + './*.js', + 'packages/**/index.js', + 'packages/size-check/**' + ], rules: { 'no-restricted-globals': 'off', 'no-restricted-syntax': 'off' diff --git a/.github/contributing.md b/.github/contributing.md index fe2ac7c114b..f7b20da2690 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 @@ -47,6 +47,7 @@ Hi! I'm really excited that you are interested in contributing to Vue.js. Before - Consider the performance / size impact of the changes, and whether the bug being fixes justifies the cost. If the bug being fixed is a very niche edge case, we should try to minimize the size / perf cost to make it worthwhile. - Is the code perf-sensitive (e.g. in "hot paths" like component updates or the vdom patch function?) + - If the branch is dev-only, performance is less of a concern. - Check how much extra bundle size the change introduces. @@ -77,6 +78,8 @@ A high level overview of tools used: **The examples below will be using the `nr` command from the [ni](https://github.com/antfu/ni) package.** You can also use plain `npm run`, but you will need to pass all additional arguments after the command after an extra `--`. For example, `nr build runtime --all` is equivalent to `npm run build -- runtime --all`. +The `run-s` and `run-p` commands found in some scripts are from [npm-run-all](https://github.com/mysticatea/npm-run-all) for orchestrating multiple scripts. `run-s` means "run in sequence" while `run-p` means "run in parallel". + ### `nr build` The `build` script builds all public packages (packages without `private: true` in their `package.json`). @@ -152,9 +155,17 @@ $ nr dev - The `dev` script supports the `-i` flag for inlining all deps. This is useful when debugging `esm-bundler` builds which externalizes deps by default. +### `nr dev-sfc` + +Shortcut for starting the SFC Playground in local dev mode. This provides the fastest feedback loop when debugging issues that can be reproduced in the SFC Playground. + +### `nr dev-esm` + +Builds and watches `vue/dist/vue-runtime.esm-bundler.js` with all deps inlined using esbuild. This is useful when debugging the ESM build in a reproductions that require real build setups: link `packages/vue` globally, then link it into the project being debugged. + ### `nr dev-compiler` -The `dev-compiler` script builds, watches and serves the [Template Explorer](https://github.com/vuejs/core/tree/main/packages/template-explorer) at `http://localhost:5000`. This is extremely useful when working on the compiler. +The `dev-compiler` script builds, watches and serves the [Template Explorer](https://github.com/vuejs/core/tree/main/packages/template-explorer) at `http://localhost:5000`. This is useful when working on pure compiler issues. ### `nr test` @@ -222,27 +233,29 @@ This is made possible via several configurations: ### Package Dependencies -``` - +---------------------+ - | | - | @vue/compiler-sfc | - | | - +-----+--------+------+ - | | - v v - +---------------------+ +----------------------+ - | | | | - +------------>| @vue/compiler-dom +--->| @vue/compiler-core | - | | | | | - +----+----+ +---------------------+ +----------------------+ - | | - | vue | - | | - +----+----+ +---------------------+ +----------------------+ +-------------------+ - | | | | | | | - +------------>| @vue/runtime-dom +--->| @vue/runtime-core +--->| @vue/reactivity | - | | | | | | - +---------------------+ +----------------------+ +-------------------+ +```mermaid + flowchart LR + compiler-sfc["@vue/compiler-sfc"] + compiler-dom["@vue/compiler-dom"] + compiler-core["@vue/compiler-core"] + vue["vue"] + runtime-dom["@vue/runtime-dom"] + runtime-core["@vue/runtime-core"] + reactivity["@vue/reactivity"] + + subgraph "Runtime Packages" + runtime-dom --> runtime-core + runtime-core --> reactivity + end + + subgraph "Compiler Packages" + compiler-sfc --> compiler-core + compiler-sfc --> compiler-dom + compiler-dom --> compiler-core + end + + vue ---> compiler-dom + vue --> runtime-dom ``` There are some rules to follow when importing across package boundaries: @@ -267,8 +280,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 abb610e319c..c811c0b8214 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,15 +17,15 @@ jobs: - uses: actions/checkout@v3 - name: Install pnpm - uses: pnpm/action-setup@v3 + uses: pnpm/action-setup@v2 - - name: Set node version to 16 + - name: Set node version to 18 uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 cache: 'pnpm' - - run: pnpm install + - run: PUPPETEER_SKIP_DOWNLOAD=1 pnpm install - name: Run unit tests run: pnpm run test-unit @@ -35,13 +35,19 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Setup cache for Chromium binary + uses: actions/cache@v3 + with: + path: ~/.cache/puppeteer/chrome + key: chromium-${{ hashFiles('pnpm-lock.yaml') }} + - name: Install pnpm uses: pnpm/action-setup@v2 - - name: Set node version to 16 + - name: Set node version to 18 uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 cache: 'pnpm' - run: pnpm install @@ -57,17 +63,20 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v2 - - name: Set node version to 16 + - name: Set node version to 18 uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 cache: 'pnpm' - - run: pnpm install + - run: PUPPETEER_SKIP_DOWNLOAD=1 pnpm install - 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 @@ -81,13 +90,13 @@ jobs: - name: Install pnpm uses: pnpm/action-setup@v2 - - name: Set node version to 16 + - name: Set node version to 18 uses: actions/setup-node@v3 with: - node-version: 16 + node-version: 18 cache: 'pnpm' - - run: pnpm install + - run: PUPPETEER_SKIP_DOWNLOAD=1 pnpm install - run: pnpm run size # - name: Check build size diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000000..1521c8b7652 --- /dev/null +++ b/.prettierignore @@ -0,0 +1 @@ +dist diff --git a/BACKERS.md b/BACKERS.md index fa66d206698..631bcb91120 100644 --- a/BACKERS.md +++ b/BACKERS.md @@ -1,6 +1,6 @@

Sponsors & Backers

-Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of the awesome sponsors and backers listed in this file. If you'd like to join them, please consider [ sponsor Vue's development](https://vuejs.org/sponsor/). +Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of the awesome sponsors and backers listed in this file. If you'd like to join them, please consider [ sponsoring Vue's development](https://vuejs.org/sponsor/).

diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fef732631a..11a2a9dde78 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( ` `) @@ -992,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({ @@ -1000,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 }) }) @@ -1019,6 +1136,36 @@ const emit = defineEmits(['a', 'b']) `) assertCode(content) }) + + // #7111 + test('withDefaults (static) w/ production mode', () => { + const { content } = compile( + ` + + `, + { isProd: true } + ) + assertCode(content) + expect(content).toMatch(`const props = __props`) + + // foo has no default value, the Function can be dropped + expect(content).toMatch(`foo: null`) + expect(content).toMatch(`bar: { type: Boolean }`) + expect(content).toMatch( + `baz: { type: [Boolean, Function], default: true }` + ) + expect(content).toMatch(`qux: { default: 'hi' }`) + }) test('withDefaults (dynamic)', () => { const { content } = compile(` @@ -1043,6 +1190,35 @@ const emit = defineEmits(['a', 'b']) ) }) + // #7111 + test('withDefaults (dynamic) w/ production mode', () => { + const { content } = compile( + ` + + `, + { isProd: true } + ) + assertCode(content) + expect(content).toMatch(`import { mergeDefaults as _mergeDefaults`) + expect(content).toMatch( + ` + _mergeDefaults({ + foo: { type: Function }, + bar: { type: Boolean }, + baz: { type: [Boolean, Function] }, + qux: null + }, { ...defaults })`.trim() + ) + }) + test('defineEmits w/ type', () => { const { content } = 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..05c7989b8f1 100644 --- a/packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts @@ -28,6 +28,26 @@ describe('sfc props transform', () => { }) }) + test('multiple variable declarations', () => { + const { content, bindings } = compile(` + + + `) + expect(content).not.toMatch(`const { foo } =`) + expect(content).toMatch(`const bar = 'fish', hello = 'world'`) + expect(content).toMatch(`_toDisplayString(hello)`) + expect(content).toMatch(`_toDisplayString(bar)`) + expect(content).toMatch(`_toDisplayString(__props.foo)`) + assertCode(content) + expect(bindings).toStrictEqual({ + foo: BindingTypes.PROPS, + bar: BindingTypes.SETUP_CONST, + hello: BindingTypes.SETUP_CONST + }) + }) + test('nested scope', () => { 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(() => @@ -229,5 +267,16 @@ describe('sfc props transform', () => { ) ).toThrow(`cannot reference locally declared variables`) }) + + test('should error if assignment to constant variable', () => { + expect(() => + compile( + `` + ) + ).toThrow(`Assignment to constant variable.`) + }) }) }) 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..6cccf40ece0 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