import { BindingTypes } from '@vue/compiler-core' import { compileSFCScript as compile, assertCode, mockId } from './utils' describe('SFC compile `) expect(content).toMatch('return { aa, bb, cc, dd, a, b, c, d, xx, x }') expect(bindings).toStrictEqual({ x: BindingTypes.SETUP_MAYBE_REF, a: BindingTypes.SETUP_LET, b: BindingTypes.SETUP_CONST, c: BindingTypes.SETUP_CONST, d: BindingTypes.SETUP_CONST, xx: BindingTypes.SETUP_MAYBE_REF, aa: BindingTypes.SETUP_LET, bb: BindingTypes.SETUP_CONST, cc: BindingTypes.SETUP_CONST, dd: BindingTypes.SETUP_CONST }) assertCode(content) }) test('binding analysis for destructure', () => { const { content, bindings } = compile(` `) expect(content).toMatch('return { foo, bar, baz, y, z }') expect(bindings).toStrictEqual({ foo: BindingTypes.SETUP_MAYBE_REF, bar: BindingTypes.SETUP_MAYBE_REF, baz: BindingTypes.SETUP_MAYBE_REF, y: BindingTypes.SETUP_MAYBE_REF, z: BindingTypes.SETUP_MAYBE_REF }) assertCode(content) }) test('defineProps()', () => { const { content, bindings } = compile(` `) // should generate working code assertCode(content) // should analyze bindings expect(bindings).toStrictEqual({ foo: BindingTypes.PROPS, bar: BindingTypes.SETUP_CONST, props: BindingTypes.SETUP_REACTIVE_CONST }) // should remove defineOptions import and call expect(content).not.toMatch('defineProps') // should generate correct setup signature expect(content).toMatch(`setup(__props, { expose }) {`) // should assign user identifier to it expect(content).toMatch(`const props = __props`) // should include context options in default export expect(content).toMatch(`export default { props: { foo: String },`) }) test('defineProps w/ external definition', () => { const { content } = compile(` `) assertCode(content) expect(content).toMatch(`export default { props: propsModel,`) }) // #4764 test('defineProps w/ leading code', () => { const { content } = compile(` `) // props declaration should be inside setup, not moved along with the import expect(content).not.toMatch(`const props = __props\nimport`) assertCode(content) }) test('defineEmits()', () => { const { content, bindings } = compile(` `) assertCode(content) expect(bindings).toStrictEqual({ myEmit: BindingTypes.SETUP_CONST }) // should remove defineOptions import and call expect(content).not.toMatch('defineEmits') // should generate correct setup signature expect(content).toMatch(`setup(__props, { expose, emit: myEmit }) {`) // should include context options in default export expect(content).toMatch(`export default { emits: ['foo', 'bar'],`) }) test('defineProps/defineEmits in multi-variable declaration', () => { 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(` `) assertCode(content) expect(content).toMatch(`props: ['item'],`) expect(content).toMatch(`emits: ['a'],`) }) test('defineExpose()', () => { const { content } = compile(` `) assertCode(content) // should remove defineOptions import and call expect(content).not.toMatch('defineExpose') // should generate correct setup signature expect(content).toMatch(`setup(__props, { expose }) {`) // should replace callee expect(content).toMatch(/\bexpose\(\{ foo: 123 \}\)/) }) test(' `) assertCode(content) }) describe(' `) assertCode(content) }) test('script setup first', () => { const { content } = compile(` `) assertCode(content) }) test('script setup first, named default export', () => { const { content } = compile(` `) assertCode(content) }) // #4395 test('script setup first, lang="ts", script block content export default', () => { const { content } = compile(` `) // ensure __default__ is declared before used expect(content).toMatch(/const __default__[\S\s]*\.\.\.__default__/m) assertCode(content) }) describe('spaces in ExportDefaultDeclaration node', () => { // #4371 test('with many spaces and newline', () => { // #4371 const { content } = compile(` `) assertCode(content) }) test('with minimal spaces', () => { const { content } = compile(` `) assertCode(content) }) }) }) describe('imports', () => { test('should hoist and expose imports', () => { assertCode( compile(``).content ) }) test('should extract comment for import or type declarations', () => { assertCode( compile(` `).content ) }) // #2740 test('should allow defineProps/Emit at the start of imports', () => { assertCode( compile(``).content ) }) test('dedupe between user & helper', () => { const { content } = compile( ` `, { reactivityTransform: true } ) assertCode(content) expect(content).toMatch(`import { ref } from 'vue'`) }) test('import dedupe between `) assertCode(content) expect(content.indexOf(`import { x }`)).toEqual( content.lastIndexOf(`import { x }`) ) }) }) // in dev mode, declared bindings are returned as an object from setup() // when using TS, users may import types which should not be returned as // values, so we need to check import usage in the template to determine // what to be returned. describe('dev mode import usage check', () => { test('components', () => { const { content } = compile(` `) // FooBar: should not be matched by plain text or incorrect case // FooBaz: used as PascalCase component // FooQux: used as kebab-case component // foo: lowercase component expect(content).toMatch(`return { fooBar, FooBaz, FooQux, foo }`) assertCode(content) }) test('directive', () => { const { content } = compile(` `) expect(content).toMatch(`return { vMyDir }`) assertCode(content) }) // https://github.com/vuejs/core/issues/4599 test('attribute expressions', () => { const { content } = compile(` `) expect(content).toMatch(`return { cond, bar, baz }`) assertCode(content) }) test('vue interpolations', () => { const { content } = compile(` `) // 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 }`) assertCode(content) }) // #4340 interpolations in template strings test('js template string interpolations', () => { const { content } = compile(` `) // VAR2 should not be matched expect(content).toMatch(`return { VAR, VAR3 }`) assertCode(content) }) // edge case: last tag in template test('last tag', () => { const { content } = compile(` `) expect(content).toMatch(`return { FooBaz, Last }`) assertCode(content) }) test('TS annotations', () => { const { content } = compile(` `) expect(content).toMatch(`return { a, b, Baz }`) assertCode(content) }) // vuejs/vue#12591 test('v-on inline statement', () => { // should not error compile(`