})"
`;
+exports[`SFC compile <script setup> > <script> and <script setup> co-usage > keep original semi style 1`] = `
+"export default {
+ props: ['item'],
+ emits: ['change'],
+ setup(__props, { expose: __expose, emit: __emit }) {
+ __expose();
+
+ console.log('test')
+ const props = __props;
+ const emit = __emit;
+ (function () {})()
+
+return { props, emit }
+}
+
+}"
+`;
+
exports[`SFC compile <script setup> > <script> and <script setup> co-usage > script first 1`] = `
"import { x } from './x'
}"
`;
-exports[`SFC compile <script setup> > defineProps/defineEmits in multi-variable declaration (full removal) 1`] = `
-"export default {
- props: ['item'],
- emits: ['a'],
- setup(__props, { expose: __expose, emit }) {
- __expose();
-
-const props = __props;
-
-
-
-return { props, emit }
-}
-
-}"
-`;
-
-exports[`SFC compile <script setup> > defineProps/defineEmits in multi-variable declaration 1`] = `
-"export default {
- props: ['item'],
- emits: ['a'],
- setup(__props, { expose: __expose, emit }) {
- __expose();
-
-const props = __props;
-
- const a = 1;
-
-return { props, a, emit }
-}
-
-}"
-`;
-
-exports[`SFC compile <script setup> > defineProps/defineEmits in multi-variable declaration fix #6757 1`] = `
-"export default {
- props: ['item'],
- emits: ['a'],
- setup(__props, { expose: __expose, emit }) {
- __expose();
-
-const props = __props;
-
- const a = 1;
-
-return { a, props, emit }
-}
-
-}"
-`;
-
-exports[`SFC compile <script setup> > defineProps/defineEmits in multi-variable declaration fix #7422 1`] = `
-"export default {
- props: ['item'],
- emits: ['foo'],
- setup(__props, { expose: __expose, emit: emits }) {
- __expose();
-
-const props = __props;
-
- const a = 0,
- b = 0;
-
-return { props, emits, a, b }
-}
-
-}"
-`;
-
exports[`SFC compile <script setup> > dev mode import usage check > TS annotations 1`] = `
"import { defineComponent as _defineComponent } from 'vue'
import { Foo, Bar, Baz, Qux, Fred } from './x'
assertCode(content)
})
- test('defineProps/defineEmits in multi-variable declaration', () => {
- const { content } = compile(`
- <script setup>
- const props = defineProps(['item']),
- a = 1,
- emit = defineEmits(['a']);
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`const a = 1;`) // test correct removal
- expect(content).toMatch(`props: ['item'],`)
- expect(content).toMatch(`emits: ['a'],`)
- })
-
- // #6757
- test('defineProps/defineEmits in multi-variable declaration fix #6757 ', () => {
- const { content } = compile(`
- <script setup>
- const a = 1,
- props = defineProps(['item']),
- emit = defineEmits(['a']);
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`const a = 1;`) // test correct removal
- expect(content).toMatch(`props: ['item'],`)
- expect(content).toMatch(`emits: ['a'],`)
- })
-
- // #7422
- test('defineProps/defineEmits in multi-variable declaration fix #7422', () => {
- const { content } = compile(`
- <script setup>
- const props = defineProps(['item']),
- emits = defineEmits(['foo']),
- a = 0,
- b = 0;
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`props: ['item'],`)
- expect(content).toMatch(`emits: ['foo'],`)
- expect(content).toMatch(`const a = 0,`)
- expect(content).toMatch(`b = 0;`)
- })
-
- test('defineProps/defineEmits in multi-variable declaration (full removal)', () => {
- const { content } = compile(`
- <script setup>
- const props = defineProps(['item']),
- emit = defineEmits(['a']);
- </script>
- `)
- assertCode(content)
- expect(content).toMatch(`props: ['item'],`)
- expect(content).toMatch(`emits: ['a'],`)
- })
-
describe('<script> and <script setup> co-usage', () => {
test('script first', () => {
const { content } = compile(`
assertCode(content)
})
+ // #7805
+ test('keep original semi style', () => {
+ const { content } = compile(`
+ <script setup>
+ console.log('test')
+ const props = defineProps(['item']);
+ const emit = defineEmits(['change']);
+ (function () {})()
+ </script>
+ `)
+ assertCode(content)
+
+ expect(content).toMatch(`console.log('test')`)
+ expect(content).toMatch(`const props = __props;`)
+ expect(content).toMatch(`const emit = __emit;`)
+ expect(content).toMatch(`(function () {})()`)
+ })
+
test('script setup first, named default export', () => {
const { content } = compile(`
<script setup>
exports[`defineEmits > basic usage 1`] = `
"export default {
emits: ['foo', 'bar'],
- setup(__props, { expose: __expose, emit: myEmit }) {
+ setup(__props, { expose: __expose, emit: __emit }) {
__expose();
-
+const myEmit = __emit
return { myEmit }
}
export default /*#__PURE__*/_defineComponent({
emits: ['a', 'b'],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose, emit: __emit }) {
__expose();
-
+const emit = __emit
return { emit }
}
export default /*#__PURE__*/_defineComponent({
emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose, emit: __emit }) {
__expose();
-
+ const emit = __emit
return { emit }
}
export default /*#__PURE__*/_defineComponent({
emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose, emit: __emit }) {
__expose();
-
+ const emit = __emit
return { emit }
}
export default /*#__PURE__*/_defineComponent({
emits: ['foo'],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose, emit: __emit }) {
__expose();
-
+ const emit: Emits = __emit
return { emit }
}
export default /*#__PURE__*/_defineComponent({
emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose, emit: __emit }) {
__expose();
-
+ const emit = __emit
return { emit }
}
export default /*#__PURE__*/_defineComponent({
emits: [\\"foo:bar\\"],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose, emit: __emit }) {
__expose();
-
+ const emit = __emit
return { emit }
}
export default /*#__PURE__*/_defineComponent({
emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose, emit: __emit }) {
__expose();
-
+ const emit = __emit
return { emit }
}
export default /*#__PURE__*/_defineComponent({
emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose, emit: __emit }) {
__expose();
-
+ const emit = __emit
return { emit }
}
export default /*#__PURE__*/_defineComponent({
emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose, emit: __emit }) {
__expose();
-
+ const emit = __emit
return { emit }
}
export default /*#__PURE__*/_defineComponent({
emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose, emit: __emit }) {
__expose();
-
+ const emit = __emit
return { emit }
}
export default /*#__PURE__*/_defineComponent({
emits: [\\"foo\\", \\"bar\\", \\"baz\\"],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose, emit: __emit }) {
__expose();
-
+ const emit = __emit
return { emit }
}
export default /*#__PURE__*/_defineComponent({
emits: [\\"some\\", \\"emit\\", \\"change\\", \\"another\\"],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose, emit: __emit }) {
__expose();
-
+ const emit = __emit;
return { emit }
}
export default /*#__PURE__*/_defineComponent({
emits: [\\"foo\\", \\"bar\\", \\"baz\\"],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose, emit: __emit }) {
__expose();
-
+ const emit = __emit
return { emit }
}
export default /*#__PURE__*/_defineComponent({
emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose, emit: __emit }) {
__expose();
-
+ const emit = __emit
return { emit }
}
export default /*#__PURE__*/_defineComponent({
emits: [\\"foo\\", \\"bar\\"],
- setup(__props, { expose: __expose, emit }) {
+ setup(__props, { expose: __expose, emit: __emit }) {
__expose();
-
+ const emit = __emit
return { emit }
}
setup(__props, { expose: __expose }) {
__expose();
-const props = __props;
-
-
+const props = __props
return { props, bar }
}
setup(__props, { expose: __expose }) {
__expose();
-const props = __props;
-
-
+const props = __props
return { props }
}
setup(__props: any, { expose: __expose }) {
__expose();
-const { foo } = __props;
-
-
+ const { foo } = __props
return { }
}
setup(__props, { expose: __expose }) {
__expose();
-const props = __props;
-
-
+ const props = __props
return { props, get propsModel() { return propsModel } }
}
props: {},
setup(__props, { expose: __expose }) {
__expose();
-
-const props = __props;
-
+const props = __props
return { props, get x() { return x } }
}
setup(__props: any, { expose: __expose }) {
__expose();
-const props = __props;
-
-
+ const props = __props
return { props, get defaults() { return defaults } }
}
setup(__props: any, { expose: __expose }) {
__expose();
-const props = __props;
-
-
+ const props = __props
return { props, get defaults() { return defaults } }
}
setup(__props: any, { expose: __expose }) {
__expose();
-const props = __props;
-
-
+ const props = __props
return { props, get defaults() { return defaults } }
}
setup(__props: any, { expose: __expose }) {
__expose();
-const props = __props;
-
-
+ const props = __props;
return { props }
}
setup(__props: any, { expose: __expose }) {
__expose();
-const props = __props;
-
-
+ const props = __props
return { props }
}
setup(__props: any, { expose: __expose }) {
__expose();
-const props = __props;
-
-
+ const props = __props
return { props }
}
setup(__props: any, { expose: __expose }) {
__expose();
-const props = __props;
-
-
+ const props = __props
return { props }
}
})"
`;
+exports[`sfc reactive props destructure > defineProps/defineEmits in multi-variable declaration (full removal) 1`] = `
+"export default {
+ props: ['item'],
+ emits: ['a'],
+ setup(__props, { emit: __emit }) {
+
+ const props = __props,
+ emit = __emit;
+
+return () => {}
+}
+
+}"
+`;
+
+exports[`sfc reactive props destructure > multi-variable declaration 1`] = `
+"export default {
+ props: ['item'],
+ setup(__props) {
+
+ const a = 1;
+
+return () => {}
+}
+
+}"
+`;
+
+exports[`sfc reactive props destructure > multi-variable declaration fix #6757 1`] = `
+"export default {
+ props: ['item'],
+ setup(__props) {
+
+ const a = 1;
+
+return () => {}
+}
+
+}"
+`;
+
+exports[`sfc reactive props destructure > multi-variable declaration fix #7422 1`] = `
+"export default {
+ props: ['item'],
+ setup(__props) {
+
+ const a = 0,
+ b = 0;
+
+return () => {}
+}
+
+}"
+`;
+
exports[`sfc reactive props destructure > multiple variable declarations 1`] = `
"import { toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock } from \\"vue\\"
props: ['foo', 'bar', 'baz'],
setup(__props) {
-const rest = _createPropsRestProxy(__props, [\\"foo\\",\\"bar\\"]);
-
-
+ const rest = _createPropsRestProxy(__props, [\\"foo\\",\\"bar\\"])
return () => {}
}
expect(content).not.toMatch('defineEmits')
// should generate correct setup signature
expect(content).toMatch(
- `setup(__props, { expose: __expose, emit: myEmit }) {`
+ `setup(__props, { expose: __expose, emit: __emit }) {`
)
+ expect(content).toMatch('const myEmit = __emit')
// should include context options in default export
expect(content).toMatch(`export default {
emits: ['foo', 'bar'],`)
assertCode(content)
expect(content).toMatch(`export default /*#__PURE__*/_defineComponent({
emits: ['a', 'b'],
- setup(__props, { expose: __expose, emit }) {`)
+ setup(__props, { expose: __expose, emit: __emit }) {`)
+ expect(content).toMatch('const emit = __emit')
})
test('w/ type', () => {
})
})
+ test('multi-variable declaration', () => {
+ const { content } = compile(`
+ <script setup>
+ const { item } = defineProps(['item']),
+ a = 1;
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`const a = 1;`)
+ expect(content).toMatch(`props: ['item'],`)
+ })
+
+ // #6757
+ test('multi-variable declaration fix #6757 ', () => {
+ const { content } = compile(`
+ <script setup>
+ const a = 1,
+ { item } = defineProps(['item']);
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`const a = 1;`)
+ expect(content).toMatch(`props: ['item'],`)
+ })
+
+ // #7422
+ test('multi-variable declaration fix #7422', () => {
+ const { content } = compile(`
+ <script setup>
+ const { item } = defineProps(['item']),
+ a = 0,
+ b = 0;
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`const a = 0,`)
+ expect(content).toMatch(`b = 0;`)
+ expect(content).toMatch(`props: ['item'],`)
+ })
+
+ test('defineProps/defineEmits in multi-variable declaration (full removal)', () => {
+ const { content } = compile(`
+ <script setup>
+ const props = defineProps(['item']),
+ emit = defineEmits(['a']);
+ </script>
+ `)
+ assertCode(content)
+ expect(content).toMatch(`props: ['item'],`)
+ expect(content).toMatch(`emits: ['a'],`)
+ })
+
describe('errors', () => {
test('should error on deep destructure', () => {
expect(() =>
(processDefineSlots(ctx, init, decl.id) ||
processDefineModel(ctx, init, decl.id))
- if (isDefineProps || isDefineEmits) {
+ if (
+ isDefineProps &&
+ !ctx.propsDestructureRestId &&
+ ctx.propsDestructureDecl
+ ) {
if (left === 1) {
ctx.s.remove(node.start! + startOffset, node.end! + startOffset)
} else {
ctx.s.remove(start, end)
left--
}
+ } else if (isDefineEmits) {
+ ctx.s.overwrite(
+ startOffset + init.start!,
+ startOffset + init.end!,
+ '__emit'
+ )
} else {
lastNonRemoved = i
}
// inject user assignment of props
// we use a default __props so that template expressions referencing props
// can use it directly
- if (ctx.propsIdentifier) {
- ctx.s.prependLeft(
- startOffset,
- `\nconst ${ctx.propsIdentifier} = __props;\n`
- )
- }
- if (ctx.propsDestructureRestId) {
- ctx.s.prependLeft(
- startOffset,
- `\nconst ${ctx.propsDestructureRestId} = ${ctx.helper(
- `createPropsRestProxy`
- )}(__props, ${JSON.stringify(
- Object.keys(ctx.propsDestructuredBindings)
- )});\n`
- )
+ if (ctx.propsDecl) {
+ if (ctx.propsDestructureRestId) {
+ ctx.s.overwrite(
+ startOffset + ctx.propsCall!.start!,
+ startOffset + ctx.propsCall!.end!,
+ `${ctx.helper(`createPropsRestProxy`)}(__props, ${JSON.stringify(
+ Object.keys(ctx.propsDestructuredBindings)
+ )})`
+ )
+ ctx.s.overwrite(
+ startOffset + ctx.propsDestructureDecl!.start!,
+ startOffset + ctx.propsDestructureDecl!.end!,
+ ctx.propsDestructureRestId
+ )
+ } else if (!ctx.propsDestructureDecl) {
+ ctx.s.overwrite(
+ startOffset + ctx.propsCall!.start!,
+ startOffset + ctx.propsCall!.end!,
+ '__props'
+ )
+ }
}
+
// inject temp variables for async context preservation
if (hasAwait) {
const any = ctx.isTS ? `: any` : ``
ctx.hasDefineExposeCall || !options.inlineTemplate
? [`expose: __expose`]
: []
- if (ctx.emitIdentifier) {
- destructureElements.push(
- ctx.emitIdentifier === `emit` ? `emit` : `emit: ${ctx.emitIdentifier}`
- )
+ if (ctx.emitDecl) {
+ destructureElements.push(`emit: __emit`)
}
if (destructureElements.length) {
args += `, { ${destructureElements.join(', ')} }`
-import { Node, ObjectPattern, Program } from '@babel/types'
+import { CallExpression, Node, ObjectPattern, Program } from '@babel/types'
import { SFCDescriptor } from '../parse'
import { generateCodeFrame } from '@vue/shared'
import { parse as babelParse, ParserPlugin } from '@babel/parser'
hasDefineModelCall = false
// defineProps
- propsIdentifier: string | undefined
+ propsCall: CallExpression | undefined
+ propsDecl: Node | undefined
propsRuntimeDecl: Node | undefined
propsTypeDecl: Node | undefined
propsDestructureDecl: ObjectPattern | undefined
// defineEmits
emitsRuntimeDecl: Node | undefined
emitsTypeDecl: Node | undefined
- emitIdentifier: string | undefined
+ emitDecl: Node | undefined
// defineModel
modelDecls: Record<string, ModelDecl> = {}
ctx.emitsTypeDecl = node.typeParameters.params[0]
}
- if (declId) {
- ctx.emitIdentifier =
- declId.type === 'Identifier' ? declId.name : ctx.getString(declId)
- }
+ ctx.emitDecl = declId
return true
}
ctx.propsTypeDecl = node.typeParameters.params[0]
}
- if (declId) {
- // handle props destructure
- if (declId.type === 'ObjectPattern') {
- processPropsDestructure(ctx, declId)
- } else {
- ctx.propsIdentifier = ctx.getString(declId)
- }
+ // handle props destructure
+ if (declId && declId.type === 'ObjectPattern') {
+ processPropsDestructure(ctx, declId)
}
+ ctx.propsCall = node
+ ctx.propsDecl = declId
+
return true
}
if (!isCallOf(node, WITH_DEFAULTS)) {
return false
}
- if (processDefineProps(ctx, node.arguments[0], declId)) {
- if (ctx.propsRuntimeDecl) {
- ctx.error(
- `${WITH_DEFAULTS} can only be used with type-based ` +
- `${DEFINE_PROPS} declaration.`,
- node
- )
- }
- if (ctx.propsDestructureDecl) {
- ctx.error(
- `${WITH_DEFAULTS}() is unnecessary when using destructure with ${DEFINE_PROPS}().\n` +
- `Prefer using destructure default values, e.g. const { foo = 1 } = defineProps(...).`,
- node.callee
- )
- }
- ctx.propsRuntimeDefaults = node.arguments[1]
- if (!ctx.propsRuntimeDefaults) {
- ctx.error(`The 2nd argument of ${WITH_DEFAULTS} is required.`, node)
- }
- } else {
+ if (!processDefineProps(ctx, node.arguments[0], declId)) {
ctx.error(
`${WITH_DEFAULTS}' first argument must be a ${DEFINE_PROPS} call.`,
node.arguments[0] || node
)
}
+
+ if (ctx.propsRuntimeDecl) {
+ ctx.error(
+ `${WITH_DEFAULTS} can only be used with type-based ` +
+ `${DEFINE_PROPS} declaration.`,
+ node
+ )
+ }
+ if (ctx.propsDestructureDecl) {
+ ctx.error(
+ `${WITH_DEFAULTS}() is unnecessary when using destructure with ${DEFINE_PROPS}().\n` +
+ `Prefer using destructure default values, e.g. const { foo = 1 } = defineProps(...).`,
+ node.callee
+ )
+ }
+ ctx.propsRuntimeDefaults = node.arguments[1]
+ if (!ctx.propsRuntimeDefaults) {
+ ctx.error(`The 2nd argument of ${WITH_DEFAULTS} is required.`, node)
+ }
+ ctx.propsCall = node
+
return true
}
declId: ObjectPattern
) {
if (!ctx.options.propsDestructure && !ctx.options.reactivityTransform) {
- ctx.propsIdentifier = ctx.getString(declId)
return
}