| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366 |
- import { parse, compileScriptSetup, SFCScriptCompileOptions } from '../src'
- import { parse as babelParse } from '@babel/parser'
- import { babelParserDefautPlugins } from '@vue/shared'
- function compile(src: string, options?: SFCScriptCompileOptions) {
- const { descriptor } = parse(src)
- return compileScriptSetup(descriptor, options)
- }
- function assertCode(code: string) {
- // parse the generated code to make sure it is valid
- try {
- babelParse(code, {
- sourceType: 'module',
- plugins: [...babelParserDefautPlugins, 'typescript']
- })
- } catch (e) {
- console.log(code)
- throw e
- }
- expect(code).toMatchSnapshot()
- }
- describe('SFC compile <script setup>', () => {
- test('should hoist imports', () => {
- assertCode(compile(`<script setup>import { ref } from 'vue'</script>`).code)
- })
- test('explicit setup signature', () => {
- assertCode(
- compile(`<script setup="props, { emit }">emit('foo')</script>`).code
- )
- })
- test('import dedupe between <script> and <script setup>', () => {
- const code = compile(`
- <script>
- import { x } from './x'
- </script>
- <script setup>
- import { x } from './x'
- x()
- </script>
- `).code
- assertCode(code)
- expect(code.indexOf(`import { x }`)).toEqual(
- code.lastIndexOf(`import { x }`)
- )
- })
- describe('exports', () => {
- test('export const x = ...', () => {
- const { code, bindings } = compile(
- `<script setup>export const x = 1</script>`
- )
- assertCode(code)
- expect(bindings).toStrictEqual({
- x: 'setup'
- })
- })
- test('export const { x } = ... (destructuring)', () => {
- const { code, bindings } = compile(`<script setup>
- export const [a = 1, { b } = { b: 123 }, ...c] = useFoo()
- export const { d = 2, _: [e], ...f } = useBar()
- </script>`)
- assertCode(code)
- expect(bindings).toStrictEqual({
- a: 'setup',
- b: 'setup',
- c: 'setup',
- d: 'setup',
- e: 'setup',
- f: 'setup'
- })
- })
- test('export function x() {}', () => {
- const { code, bindings } = compile(
- `<script setup>export function x(){}</script>`
- )
- assertCode(code)
- expect(bindings).toStrictEqual({
- x: 'setup'
- })
- })
- test('export class X() {}', () => {
- const { code, bindings } = compile(
- `<script setup>export class X {}</script>`
- )
- assertCode(code)
- expect(bindings).toStrictEqual({
- X: 'setup'
- })
- })
- test('export { x }', () => {
- const { code, bindings } = compile(
- `<script setup>
- const x = 1
- const y = 2
- export { x, y }
- </script>`
- )
- assertCode(code)
- expect(bindings).toStrictEqual({
- x: 'setup',
- y: 'setup'
- })
- })
- test(`export { x } from './x'`, () => {
- const { code, bindings } = compile(
- `<script setup>
- export { x, y } from './x'
- </script>`
- )
- assertCode(code)
- expect(bindings).toStrictEqual({
- x: 'setup',
- y: 'setup'
- })
- })
- test(`export default from './x'`, () => {
- const { code, bindings } = compile(
- `<script setup>
- export default from './x'
- </script>`,
- {
- parserPlugins: ['exportDefaultFrom']
- }
- )
- assertCode(code)
- expect(bindings).toStrictEqual({})
- })
- test(`export { x as default }`, () => {
- const { code, bindings } = compile(
- `<script setup>
- import x from './x'
- const y = 1
- export { x as default, y }
- </script>`
- )
- assertCode(code)
- expect(bindings).toStrictEqual({
- y: 'setup'
- })
- })
- test(`export { x as default } from './x'`, () => {
- const { code, bindings } = compile(
- `<script setup>
- export { x as default, y } from './x'
- </script>`
- )
- assertCode(code)
- expect(bindings).toStrictEqual({
- y: 'setup'
- })
- })
- test(`export * from './x'`, () => {
- const { code, bindings } = compile(
- `<script setup>
- export * from './x'
- export const y = 1
- </script>`
- )
- assertCode(code)
- expect(bindings).toStrictEqual({
- y: 'setup'
- // in this case we cannot extract bindings from ./x so it falls back
- // to runtime proxy dispatching
- })
- })
- test('export default in <script setup>', () => {
- const { code, bindings } = compile(
- `<script setup>
- export default {
- props: ['foo']
- }
- export const y = 1
- </script>`
- )
- assertCode(code)
- expect(bindings).toStrictEqual({
- y: 'setup'
- })
- })
- })
- describe('<script setup lang="ts">', () => {
- test('hoist type declarations', () => {
- const { code, bindings } = compile(`
- <script setup lang="ts">
- export interface Foo {}
- type Bar = {}
- export const a = 1
- </script>`)
- assertCode(code)
- expect(bindings).toStrictEqual({ a: 'setup' })
- })
- test('extract props', () => {})
- test('extract emits', () => {})
- })
- describe('errors', () => {
- test('must have <script setup>', () => {
- expect(() => compile(`<script>foo()</script>`)).toThrow(
- `SFC has no <script setup>`
- )
- })
- test('<script> and <script setup> must have same lang', () => {
- expect(() =>
- compile(`<script>foo()</script><script setup lang="ts">bar()</script>`)
- ).toThrow(`<script> and <script setup> must have the same language type`)
- })
- test('export local as default', () => {
- expect(() =>
- compile(`<script setup>
- const bar = 1
- export { bar as default }
- </script>`)
- ).toThrow(`Cannot export locally defined variable as default`)
- })
- test('export default referencing local var', () => {
- expect(() =>
- compile(`<script setup>
- const bar = 1
- export default {
- props: {
- foo: {
- default: () => bar
- }
- }
- }
- </script>`)
- ).toThrow(`cannot reference locally declared variables`)
- })
- test('export default referencing exports', () => {
- expect(() =>
- compile(`<script setup>
- export const bar = 1
- export default {
- props: bar
- }
- </script>`)
- ).toThrow(`cannot reference locally declared variables`)
- })
- test('should allow export default referencing scope var', () => {
- assertCode(
- compile(`<script setup>
- const bar = 1
- export default {
- props: {
- foo: {
- default: bar => bar + 1
- }
- }
- }
- </script>`).code
- )
- })
- test('should allow export default referencing imported binding', () => {
- assertCode(
- compile(`<script setup>
- import { bar } from './bar'
- export { bar }
- export default {
- props: {
- foo: {
- default: () => bar
- }
- }
- }
- </script>`).code
- )
- })
- test('should allow export default referencing re-exported binding', () => {
- assertCode(
- compile(`<script setup>
- export { bar } from './bar'
- export default {
- props: {
- foo: {
- default: () => bar
- }
- }
- }
- </script>`).code
- )
- })
- test('error on duplicated defalut export', () => {
- expect(() =>
- compile(`
- <script>
- export default {}
- </script>
- <script setup>
- export default {}
- </script>
- `)
- ).toThrow(`Default export is already declared`)
- expect(() =>
- compile(`
- <script>
- export default {}
- </script>
- <script setup>
- const x = {}
- export { x as default }
- </script>
- `)
- ).toThrow(`Default export is already declared`)
- expect(() =>
- compile(`
- <script>
- export default {}
- </script>
- <script setup>
- export { x as default } from './y'
- </script>
- `)
- ).toThrow(`Default export is already declared`)
- expect(() =>
- compile(`
- <script>
- export { x as default } from './y'
- </script>
- <script setup>
- export default {}
- </script>
- `)
- ).toThrow(`Default export is already declared`)
- expect(() =>
- compile(`
- <script>
- const x = {}
- export { x as default }
- </script>
- <script setup>
- export default {}
- </script>
- `)
- ).toThrow(`Default export is already declared`)
- })
- })
- })
|