forked from vuejs/core
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(compiler-sfc):
<script setup>
defineProps destructure transform (
- Loading branch information
Showing
14 changed files
with
716 additions
and
123 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
128 changes: 128 additions & 0 deletions
128
packages/compiler-sfc/__tests__/__snapshots__/compileScriptPropsTransform.spec.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`sfc props transform aliasing 1`] = ` | ||
"import { toDisplayString as _toDisplayString } from \\"vue\\" | ||
export default { | ||
props: ['foo'], | ||
setup(__props) { | ||
let x = foo | ||
let y = __props.foo | ||
return (_ctx, _cache) => { | ||
return _toDisplayString(__props.foo + __props.foo) | ||
} | ||
} | ||
}" | ||
`; | ||
|
||
exports[`sfc props transform basic usage 1`] = ` | ||
"import { toDisplayString as _toDisplayString } from \\"vue\\" | ||
export default { | ||
props: ['foo'], | ||
setup(__props) { | ||
console.log(__props.foo) | ||
return (_ctx, _cache) => { | ||
return _toDisplayString(__props.foo) | ||
} | ||
} | ||
}" | ||
`; | ||
|
||
exports[`sfc props transform default values w/ runtime declaration 1`] = ` | ||
"import { mergeDefaults as _mergeDefaults } from 'vue' | ||
export default { | ||
props: _mergeDefaults(['foo', 'bar'], { | ||
foo: 1, | ||
bar: () => {} | ||
}), | ||
setup(__props) { | ||
return () => {} | ||
} | ||
}" | ||
`; | ||
|
||
exports[`sfc props transform default values w/ type declaration 1`] = ` | ||
"import { defineComponent as _defineComponent } from 'vue' | ||
export default /*#__PURE__*/_defineComponent({ | ||
props: { | ||
foo: { type: Number, required: false, default: 1 }, | ||
bar: { type: Object, required: false, default: () => {} } | ||
}, | ||
setup(__props: any) { | ||
return () => {} | ||
} | ||
})" | ||
`; | ||
|
||
exports[`sfc props transform default values w/ type declaration, prod mode 1`] = ` | ||
"import { defineComponent as _defineComponent } from 'vue' | ||
export default /*#__PURE__*/_defineComponent({ | ||
props: { | ||
foo: { default: 1 }, | ||
bar: { default: () => {} }, | ||
baz: null | ||
}, | ||
setup(__props: any) { | ||
return () => {} | ||
} | ||
})" | ||
`; | ||
|
||
exports[`sfc props transform nested scope 1`] = ` | ||
"export default { | ||
props: ['foo', 'bar'], | ||
setup(__props) { | ||
function test(foo) { | ||
console.log(foo) | ||
console.log(__props.bar) | ||
} | ||
return () => {} | ||
} | ||
}" | ||
`; | ||
|
||
exports[`sfc props transform rest spread 1`] = ` | ||
"import { createPropsRestProxy as _createPropsRestProxy } from 'vue' | ||
export default { | ||
props: ['foo', 'bar', 'baz'], | ||
setup(__props) { | ||
const rest = _createPropsRestProxy(__props, [\\"foo\\",\\"bar\\"]) | ||
return () => {} | ||
} | ||
}" | ||
`; |
191 changes: 191 additions & 0 deletions
191
packages/compiler-sfc/__tests__/compileScriptPropsTransform.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
import { BindingTypes } from '@vue/compiler-core' | ||
import { SFCScriptCompileOptions } from '../src' | ||
import { compileSFCScript, assertCode } from './utils' | ||
|
||
describe('sfc props transform', () => { | ||
function compile(src: string, options?: Partial<SFCScriptCompileOptions>) { | ||
return compileSFCScript(src, { | ||
inlineTemplate: true, | ||
propsDestructureTransform: true, | ||
...options | ||
}) | ||
} | ||
|
||
test('basic usage', () => { | ||
const { content, bindings } = compile(` | ||
<script setup> | ||
const { foo } = defineProps(['foo']) | ||
console.log(foo) | ||
</script> | ||
<template>{{ foo }}</template> | ||
`) | ||
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 | ||
}) | ||
}) | ||
|
||
test('nested scope', () => { | ||
const { content, bindings } = compile(` | ||
<script setup> | ||
const { foo, bar } = defineProps(['foo', 'bar']) | ||
function test(foo) { | ||
console.log(foo) | ||
console.log(bar) | ||
} | ||
</script> | ||
`) | ||
expect(content).not.toMatch(`const { foo, bar } =`) | ||
expect(content).toMatch(`console.log(foo)`) | ||
expect(content).toMatch(`console.log(__props.bar)`) | ||
assertCode(content) | ||
expect(bindings).toStrictEqual({ | ||
foo: BindingTypes.PROPS, | ||
bar: BindingTypes.PROPS, | ||
test: BindingTypes.SETUP_CONST | ||
}) | ||
}) | ||
|
||
test('default values w/ runtime declaration', () => { | ||
const { content } = compile(` | ||
<script setup> | ||
const { foo = 1, bar = {} } = defineProps(['foo', 'bar']) | ||
</script> | ||
`) | ||
// literals can be used as-is, non-literals are always returned from a | ||
// function | ||
expect(content).toMatch(`props: _mergeDefaults(['foo', 'bar'], { | ||
foo: 1, | ||
bar: () => {} | ||
})`) | ||
assertCode(content) | ||
}) | ||
|
||
test('default values w/ type declaration', () => { | ||
const { content } = compile(` | ||
<script setup lang="ts"> | ||
const { foo = 1, bar = {} } = defineProps<{ foo?: number, bar?: object }>() | ||
</script> | ||
`) | ||
// literals can be used as-is, non-literals are always returned from a | ||
// function | ||
expect(content).toMatch(`props: { | ||
foo: { type: Number, required: false, default: 1 }, | ||
bar: { type: Object, required: false, default: () => {} } | ||
}`) | ||
assertCode(content) | ||
}) | ||
|
||
test('default values w/ type declaration, prod mode', () => { | ||
const { content } = compile( | ||
` | ||
<script setup lang="ts"> | ||
const { foo = 1, bar = {} } = defineProps<{ foo?: number, bar?: object, baz?: any }>() | ||
</script> | ||
`, | ||
{ isProd: true } | ||
) | ||
// literals can be used as-is, non-literals are always returned from a | ||
// function | ||
expect(content).toMatch(`props: { | ||
foo: { default: 1 }, | ||
bar: { default: () => {} }, | ||
baz: null | ||
}`) | ||
assertCode(content) | ||
}) | ||
|
||
test('aliasing', () => { | ||
const { content, bindings } = compile(` | ||
<script setup> | ||
const { foo: bar } = defineProps(['foo']) | ||
let x = foo | ||
let y = bar | ||
</script> | ||
<template>{{ foo + bar }}</template> | ||
`) | ||
expect(content).not.toMatch(`const { foo: bar } =`) | ||
expect(content).toMatch(`let x = foo`) // should not process | ||
expect(content).toMatch(`let y = __props.foo`) | ||
// should convert bar to __props.foo in template expressions | ||
expect(content).toMatch(`_toDisplayString(__props.foo + __props.foo)`) | ||
assertCode(content) | ||
expect(bindings).toStrictEqual({ | ||
x: BindingTypes.SETUP_LET, | ||
y: BindingTypes.SETUP_LET, | ||
foo: BindingTypes.PROPS, | ||
bar: BindingTypes.PROPS_ALIASED, | ||
__propsAliases: { | ||
bar: 'foo' | ||
} | ||
}) | ||
}) | ||
|
||
test('rest spread', () => { | ||
const { content, bindings } = compile(` | ||
<script setup> | ||
const { foo, bar, ...rest } = defineProps(['foo', 'bar', 'baz']) | ||
</script> | ||
`) | ||
expect(content).toMatch( | ||
`const rest = _createPropsRestProxy(__props, ["foo","bar"])` | ||
) | ||
assertCode(content) | ||
expect(bindings).toStrictEqual({ | ||
foo: BindingTypes.PROPS, | ||
bar: BindingTypes.PROPS, | ||
baz: BindingTypes.PROPS, | ||
rest: BindingTypes.SETUP_CONST | ||
}) | ||
}) | ||
|
||
describe('errors', () => { | ||
test('should error on deep destructure', () => { | ||
expect(() => | ||
compile( | ||
`<script setup>const { foo: [bar] } = defineProps(['foo'])</script>` | ||
) | ||
).toThrow(`destructure does not support nested patterns`) | ||
|
||
expect(() => | ||
compile( | ||
`<script setup>const { foo: { bar } } = defineProps(['foo'])</script>` | ||
) | ||
).toThrow(`destructure does not support nested patterns`) | ||
}) | ||
|
||
test('should error on computed key', () => { | ||
expect(() => | ||
compile( | ||
`<script setup>const { [foo]: bar } = defineProps(['foo'])</script>` | ||
) | ||
).toThrow(`destructure cannot use computed key`) | ||
}) | ||
|
||
test('should error when used with withDefaults', () => { | ||
expect(() => | ||
compile( | ||
`<script setup lang="ts"> | ||
const { foo } = withDefaults(defineProps<{ foo: string }>(), { foo: 'foo' }) | ||
</script>` | ||
) | ||
).toThrow(`withDefaults() is unnecessary when using destructure`) | ||
}) | ||
|
||
test('should error if destructure reference local vars', () => { | ||
expect(() => | ||
compile( | ||
`<script setup> | ||
const x = 1 | ||
const { | ||
foo = () => x | ||
} = defineProps(['foo']) | ||
</script>` | ||
) | ||
).toThrow(`cannot reference locally declared variables`) | ||
}) | ||
}) | ||
}) |
Oops, something went wrong.