compileScript.spec.ts 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553
  1. import { BindingTypes } from '@vue/compiler-core'
  2. import { compileSFCScript as compile, assertCode, mockId } from './utils'
  3. describe('SFC compile <script setup>', () => {
  4. test('should compile JS syntax', () => {
  5. const { content } = compile(`
  6. <script setup lang='js'>
  7. const a = 1
  8. const b = 2
  9. </script>
  10. `)
  11. expect(content).toMatch(`return { a, b }`)
  12. assertCode(content)
  13. })
  14. test('should expose top level declarations', () => {
  15. const { content, bindings } = compile(`
  16. <script setup>
  17. import { x } from './x'
  18. let a = 1
  19. const b = 2
  20. function c() {}
  21. class d {}
  22. </script>
  23. <script>
  24. import { xx } from './x'
  25. let aa = 1
  26. const bb = 2
  27. function cc() {}
  28. class dd {}
  29. </script>
  30. `)
  31. expect(content).toMatch(
  32. `return { get aa() { return aa }, set aa(v) { aa = v }, ` +
  33. `bb, cc, dd, get a() { return a }, set a(v) { a = v }, b, c, d, ` +
  34. `get xx() { return xx }, get x() { return x } }`
  35. )
  36. expect(bindings).toStrictEqual({
  37. x: BindingTypes.SETUP_MAYBE_REF,
  38. a: BindingTypes.SETUP_LET,
  39. b: BindingTypes.SETUP_CONST,
  40. c: BindingTypes.SETUP_CONST,
  41. d: BindingTypes.SETUP_CONST,
  42. xx: BindingTypes.SETUP_MAYBE_REF,
  43. aa: BindingTypes.SETUP_LET,
  44. bb: BindingTypes.LITERAL_CONST,
  45. cc: BindingTypes.SETUP_CONST,
  46. dd: BindingTypes.SETUP_CONST
  47. })
  48. assertCode(content)
  49. })
  50. test('binding analysis for destructure', () => {
  51. const { content, bindings } = compile(`
  52. <script setup>
  53. const { foo, b: bar, ['x' + 'y']: baz, x: { y, zz: { z }}} = {}
  54. </script>
  55. `)
  56. expect(content).toMatch('return { foo, bar, baz, y, z }')
  57. expect(bindings).toStrictEqual({
  58. foo: BindingTypes.SETUP_MAYBE_REF,
  59. bar: BindingTypes.SETUP_MAYBE_REF,
  60. baz: BindingTypes.SETUP_MAYBE_REF,
  61. y: BindingTypes.SETUP_MAYBE_REF,
  62. z: BindingTypes.SETUP_MAYBE_REF
  63. })
  64. assertCode(content)
  65. })
  66. describe('<script> and <script setup> co-usage', () => {
  67. test('script first', () => {
  68. const { content } = compile(`
  69. <script>
  70. export const n = 1
  71. export default {}
  72. </script>
  73. <script setup>
  74. import { x } from './x'
  75. x()
  76. </script>
  77. `)
  78. assertCode(content)
  79. })
  80. test('script setup first', () => {
  81. const { content } = compile(`
  82. <script setup>
  83. import { x } from './x'
  84. x()
  85. </script>
  86. <script>
  87. export const n = 1
  88. export default {}
  89. </script>
  90. `)
  91. assertCode(content)
  92. })
  93. // #7805
  94. test('keep original semi style', () => {
  95. const { content } = compile(`
  96. <script setup>
  97. console.log('test')
  98. const props = defineProps(['item']);
  99. const emit = defineEmits(['change']);
  100. (function () {})()
  101. </script>
  102. `)
  103. assertCode(content)
  104. expect(content).toMatch(`console.log('test')`)
  105. expect(content).toMatch(`const props = __props;`)
  106. expect(content).toMatch(`const emit = __emit;`)
  107. expect(content).toMatch(`(function () {})()`)
  108. })
  109. test('script setup first, named default export', () => {
  110. const { content } = compile(`
  111. <script setup>
  112. import { x } from './x'
  113. x()
  114. </script>
  115. <script>
  116. export const n = 1
  117. const def = {}
  118. export { def as default }
  119. </script>
  120. `)
  121. assertCode(content)
  122. })
  123. // #4395
  124. test('script setup first, lang="ts", script block content export default', () => {
  125. const { content } = compile(`
  126. <script setup lang="ts">
  127. import { x } from './x'
  128. x()
  129. </script>
  130. <script lang="ts">
  131. export default {
  132. name: "test"
  133. }
  134. </script>
  135. `)
  136. // ensure __default__ is declared before used
  137. expect(content).toMatch(/const __default__[\S\s]*\.\.\.__default__/m)
  138. assertCode(content)
  139. })
  140. describe('spaces in ExportDefaultDeclaration node', () => {
  141. // #4371
  142. test('with many spaces and newline', () => {
  143. // #4371
  144. const { content } = compile(`
  145. <script>
  146. export const n = 1
  147. export default
  148. {
  149. some:'option'
  150. }
  151. </script>
  152. <script setup>
  153. import { x } from './x'
  154. x()
  155. </script>
  156. `)
  157. assertCode(content)
  158. })
  159. test('with minimal spaces', () => {
  160. const { content } = compile(`
  161. <script>
  162. export const n = 1
  163. export default{
  164. some:'option'
  165. }
  166. </script>
  167. <script setup>
  168. import { x } from './x'
  169. x()
  170. </script>
  171. `)
  172. assertCode(content)
  173. })
  174. })
  175. test('export call expression as default', () => {
  176. const { content } = compile(`
  177. <script>
  178. function fn() {
  179. return "hello, world";
  180. }
  181. export default fn();
  182. </script>
  183. <script setup>
  184. console.log('foo')
  185. </script>
  186. `)
  187. assertCode(content)
  188. })
  189. })
  190. describe('imports', () => {
  191. test('should hoist and expose imports', () => {
  192. assertCode(
  193. compile(`<script setup>
  194. import { ref } from 'vue'
  195. import 'foo/css'
  196. </script>`).content
  197. )
  198. })
  199. test('should extract comment for import or type declarations', () => {
  200. assertCode(
  201. compile(`
  202. <script setup>
  203. import a from 'a' // comment
  204. import b from 'b'
  205. </script>
  206. `).content
  207. )
  208. })
  209. // #2740
  210. test('should allow defineProps/Emit at the start of imports', () => {
  211. assertCode(
  212. compile(`<script setup>
  213. import { ref } from 'vue'
  214. defineProps(['foo'])
  215. defineEmits(['bar'])
  216. const r = ref(0)
  217. </script>`).content
  218. )
  219. })
  220. test('dedupe between user & helper', () => {
  221. const { content } = compile(
  222. `
  223. <script setup>
  224. import { ref } from 'vue'
  225. let foo = $ref(1)
  226. </script>
  227. `,
  228. { reactivityTransform: true }
  229. )
  230. assertCode(content)
  231. expect(content).toMatch(`import { ref } from 'vue'`)
  232. })
  233. test('import dedupe between <script> and <script setup>', () => {
  234. const { content } = compile(`
  235. <script>
  236. import { x } from './x'
  237. </script>
  238. <script setup>
  239. import { x } from './x'
  240. x()
  241. </script>
  242. `)
  243. assertCode(content)
  244. expect(content.indexOf(`import { x }`)).toEqual(
  245. content.lastIndexOf(`import { x }`)
  246. )
  247. })
  248. describe('import ref/reactive function from other place', () => {
  249. test('import directly', () => {
  250. const { bindings } = compile(`
  251. <script setup>
  252. import { ref, reactive } from './foo'
  253. const foo = ref(1)
  254. const bar = reactive(1)
  255. </script>
  256. `)
  257. expect(bindings).toStrictEqual({
  258. ref: BindingTypes.SETUP_MAYBE_REF,
  259. reactive: BindingTypes.SETUP_MAYBE_REF,
  260. foo: BindingTypes.SETUP_MAYBE_REF,
  261. bar: BindingTypes.SETUP_MAYBE_REF
  262. })
  263. })
  264. test('import w/ alias', () => {
  265. const { bindings } = compile(`
  266. <script setup>
  267. import { ref as _ref, reactive as _reactive } from './foo'
  268. const foo = ref(1)
  269. const bar = reactive(1)
  270. </script>
  271. `)
  272. expect(bindings).toStrictEqual({
  273. _reactive: BindingTypes.SETUP_MAYBE_REF,
  274. _ref: BindingTypes.SETUP_MAYBE_REF,
  275. foo: BindingTypes.SETUP_MAYBE_REF,
  276. bar: BindingTypes.SETUP_MAYBE_REF
  277. })
  278. })
  279. test('aliased usage before import site', () => {
  280. const { bindings } = compile(`
  281. <script setup>
  282. const bar = x(1)
  283. import { reactive as x } from 'vue'
  284. </script>
  285. `)
  286. expect(bindings).toStrictEqual({
  287. bar: BindingTypes.SETUP_REACTIVE_CONST,
  288. x: BindingTypes.SETUP_CONST
  289. })
  290. })
  291. })
  292. test('should support module string names syntax', () => {
  293. const { content, bindings } = compile(`
  294. <script>
  295. import { "😏" as foo } from './foo'
  296. </script>
  297. <script setup>
  298. import { "😏" as foo } from './foo'
  299. </script>
  300. `)
  301. assertCode(content)
  302. expect(bindings).toStrictEqual({
  303. foo: BindingTypes.SETUP_MAYBE_REF
  304. })
  305. })
  306. })
  307. // in dev mode, declared bindings are returned as an object from setup()
  308. // when using TS, users may import types which should not be returned as
  309. // values, so we need to check import usage in the template to determine
  310. // what to be returned.
  311. describe('dev mode import usage check', () => {
  312. test('components', () => {
  313. const { content } = compile(`
  314. <script setup lang="ts">
  315. import { FooBar, FooBaz, FooQux, foo } from './x'
  316. const fooBar: FooBar = 1
  317. </script>
  318. <template>
  319. <FooBaz></FooBaz>
  320. <foo-qux/>
  321. <foo/>
  322. FooBar
  323. </template>
  324. `)
  325. // FooBar: should not be matched by plain text or incorrect case
  326. // FooBaz: used as PascalCase component
  327. // FooQux: used as kebab-case component
  328. // foo: lowercase component
  329. expect(content).toMatch(
  330. `return { fooBar, get FooBaz() { return FooBaz }, ` +
  331. `get FooQux() { return FooQux }, get foo() { return foo } }`
  332. )
  333. assertCode(content)
  334. })
  335. test('directive', () => {
  336. const { content } = compile(`
  337. <script setup lang="ts">
  338. import { vMyDir } from './x'
  339. </script>
  340. <template>
  341. <div v-my-dir></div>
  342. </template>
  343. `)
  344. expect(content).toMatch(`return { get vMyDir() { return vMyDir } }`)
  345. assertCode(content)
  346. })
  347. test('dynamic arguments', () => {
  348. const { content } = compile(`
  349. <script setup lang="ts">
  350. import { FooBar, foo, bar, unused } from './x'
  351. </script>
  352. <template>
  353. <FooBar #[foo.slotName] />
  354. <FooBar #unused />
  355. <div :[bar.attrName]="15"></div>
  356. <div unused="unused"></div>
  357. </template>
  358. `)
  359. expect(content).toMatch(
  360. `return { get FooBar() { return FooBar }, get foo() { return foo }, ` +
  361. `get bar() { return bar } }`
  362. )
  363. assertCode(content)
  364. })
  365. // https://github.com/vuejs/core/issues/4599
  366. test('attribute expressions', () => {
  367. const { content } = compile(`
  368. <script setup lang="ts">
  369. import { bar, baz } from './x'
  370. const cond = true
  371. </script>
  372. <template>
  373. <div :class="[cond ? '' : bar(), 'default']" :style="baz"></div>
  374. </template>
  375. `)
  376. expect(content).toMatch(
  377. `return { cond, get bar() { return bar }, get baz() { return baz } }`
  378. )
  379. assertCode(content)
  380. })
  381. test('vue interpolations', () => {
  382. const { content } = compile(`
  383. <script setup lang="ts">
  384. import { x, y, z, x$y } from './x'
  385. </script>
  386. <template>
  387. <div :id="z + 'y'">{{ x }} {{ yy }} {{ x$y }}</div>
  388. </template>
  389. `)
  390. // x: used in interpolation
  391. // y: should not be matched by {{ yy }} or 'y' in binding exps
  392. // x$y: #4274 should escape special chars when creating Regex
  393. expect(content).toMatch(
  394. `return { get x() { return x }, get z() { return z }, get x$y() { return x$y } }`
  395. )
  396. assertCode(content)
  397. })
  398. // #4340 interpolations in template strings
  399. test('js template string interpolations', () => {
  400. const { content } = compile(`
  401. <script setup lang="ts">
  402. import { VAR, VAR2, VAR3 } from './x'
  403. </script>
  404. <template>
  405. {{ \`\${VAR}VAR2\${VAR3}\` }}
  406. </template>
  407. `)
  408. // VAR2 should not be matched
  409. expect(content).toMatch(
  410. `return { get VAR() { return VAR }, get VAR3() { return VAR3 } }`
  411. )
  412. assertCode(content)
  413. })
  414. // edge case: last tag in template
  415. test('last tag', () => {
  416. const { content } = compile(`
  417. <script setup lang="ts">
  418. import { FooBaz, Last } from './x'
  419. </script>
  420. <template>
  421. <FooBaz></FooBaz>
  422. <Last/>
  423. </template>
  424. `)
  425. expect(content).toMatch(
  426. `return { get FooBaz() { return FooBaz }, get Last() { return Last } }`
  427. )
  428. assertCode(content)
  429. })
  430. test('TS annotations', () => {
  431. const { content } = compile(`
  432. <script setup lang="ts">
  433. import { Foo, Bar, Baz, Qux, Fred } from './x'
  434. const a = 1
  435. function b() {}
  436. </script>
  437. <template>
  438. {{ a as Foo }}
  439. {{ b<Bar>() }}
  440. {{ Baz }}
  441. <Comp v-slot="{ data }: Qux">{{ data }}</Comp>
  442. <div v-for="{ z = x as Qux } in list as Fred"/>
  443. </template>
  444. `)
  445. expect(content).toMatch(`return { a, b, get Baz() { return Baz } }`)
  446. assertCode(content)
  447. })
  448. // vuejs/vue#12591
  449. test('v-on inline statement', () => {
  450. // should not error
  451. compile(`
  452. <script setup lang="ts">
  453. import { foo } from './foo'
  454. </script>
  455. <template>
  456. <div @click="$emit('update:a');"></div>
  457. </template>
  458. `)
  459. })
  460. test('template ref', () => {
  461. const { content } = compile(`
  462. <script setup lang="ts">
  463. import { foo, bar, Baz } from './foo'
  464. </script>
  465. <template>
  466. <div ref="foo"></div>
  467. <div ref=""></div>
  468. <Baz ref="bar" />
  469. </template>
  470. `)
  471. expect(content).toMatch(
  472. 'return { get foo() { return foo }, get bar() { return bar }, get Baz() { return Baz } }'
  473. )
  474. assertCode(content)
  475. })
  476. })
  477. describe('inlineTemplate mode', () => {
  478. test('should work', () => {
  479. const { content } = compile(
  480. `
  481. <script setup>
  482. import { ref } from 'vue'
  483. const count = ref(0)
  484. </script>
  485. <template>
  486. <div>{{ count }}</div>
  487. <div>static</div>
  488. </template>
  489. `,
  490. { inlineTemplate: true }
  491. )
  492. // check snapshot and make sure helper imports and
  493. // hoists are placed correctly.
  494. assertCode(content)
  495. // in inline mode, no need to call expose() since nothing is exposed
  496. // anyway!
  497. expect(content).not.toMatch(`expose()`)
  498. })
  499. test('with defineExpose()', () => {
  500. const { content } = compile(
  501. `
  502. <script setup>
  503. const count = ref(0)
  504. defineExpose({ count })
  505. </script>
  506. `,
  507. { inlineTemplate: true }
  508. )
  509. assertCode(content)
  510. expect(content).toMatch(`setup(__props, { expose: __expose })`)
  511. expect(content).toMatch(`expose({ count })`)
  512. })
  513. test('referencing scope components and directives', () => {
  514. const { content } = compile(
  515. `
  516. <script setup>
  517. import ChildComp from './Child.vue'
  518. import SomeOtherComp from './Other.vue'
  519. import vMyDir from './my-dir'
  520. </script>
  521. <template>
  522. <div v-my-dir></div>
  523. <ChildComp/>
  524. <some-other-comp/>
  525. </template>
  526. `,
  527. { inlineTemplate: true }
  528. )
  529. expect(content).toMatch('[_unref(vMyDir)]')
  530. expect(content).toMatch('_createVNode(ChildComp)')
  531. // kebab-case component support
  532. expect(content).toMatch('_createVNode(SomeOtherComp)')
  533. assertCode(content)
  534. })
  535. test('avoid unref() when necessary', () => {
  536. // function, const, component import
  537. const { content } = compile(
  538. `<script setup>
  539. import { ref } from 'vue'
  540. import Foo, { bar } from './Foo.vue'
  541. import other from './util'
  542. import * as tree from './tree'
  543. const count = ref(0)
  544. const constant = {}
  545. const maybe = foo()
  546. let lett = 1
  547. function fn() {}
  548. </script>
  549. <template>
  550. <Foo>{{ bar }}</Foo>
  551. <div @click="fn">{{ count }} {{ constant }} {{ maybe }} {{ lett }} {{ other }}</div>
  552. {{ tree.foo() }}
  553. </template>
  554. `,
  555. { inlineTemplate: true }
  556. )
  557. // no need to unref vue component import
  558. expect(content).toMatch(`createVNode(Foo,`)
  559. // #2699 should unref named imports from .vue
  560. expect(content).toMatch(`unref(bar)`)
  561. // should unref other imports
  562. expect(content).toMatch(`unref(other)`)
  563. // no need to unref constant literals
  564. expect(content).not.toMatch(`unref(constant)`)
  565. // should directly use .value for known refs
  566. expect(content).toMatch(`count.value`)
  567. // should unref() on const bindings that may be refs
  568. expect(content).toMatch(`unref(maybe)`)
  569. // should unref() on let bindings
  570. expect(content).toMatch(`unref(lett)`)
  571. // no need to unref namespace import (this also preserves tree-shaking)
  572. expect(content).toMatch(`tree.foo()`)
  573. // no need to unref function declarations
  574. expect(content).toMatch(`{ onClick: fn }`)
  575. // no need to mark constant fns in patch flag
  576. expect(content).not.toMatch(`PROPS`)
  577. assertCode(content)
  578. })
  579. test('v-model codegen', () => {
  580. const { content } = compile(
  581. `<script setup>
  582. import { ref } from 'vue'
  583. const count = ref(0)
  584. const maybe = foo()
  585. let lett = 1
  586. </script>
  587. <template>
  588. <input v-model="count">
  589. <input v-model="maybe">
  590. <input v-model="lett">
  591. </template>
  592. `,
  593. { inlineTemplate: true }
  594. )
  595. // known const ref: set value
  596. expect(content).toMatch(`(count).value = $event`)
  597. // const but maybe ref: assign if ref, otherwise do nothing
  598. expect(content).toMatch(`_isRef(maybe) ? (maybe).value = $event : null`)
  599. // let: handle both cases
  600. expect(content).toMatch(
  601. `_isRef(lett) ? (lett).value = $event : lett = $event`
  602. )
  603. assertCode(content)
  604. })
  605. test('v-model should not generate ref assignment code for non-setup bindings', () => {
  606. const { content } = compile(
  607. `<script setup>
  608. import { ref } from 'vue'
  609. const count = ref(0)
  610. </script>
  611. <script>
  612. export default {
  613. data() { return { foo: 123 } }
  614. }
  615. </script>
  616. <template>
  617. <input v-model="foo">
  618. </template>
  619. `,
  620. { inlineTemplate: true }
  621. )
  622. expect(content).not.toMatch(`_isRef(foo)`)
  623. })
  624. test('template assignment expression codegen', () => {
  625. const { content } = compile(
  626. `<script setup>
  627. import { ref } from 'vue'
  628. const count = ref(0)
  629. const maybe = foo()
  630. let lett = 1
  631. let v = ref(1)
  632. </script>
  633. <template>
  634. <div @click="count = 1"/>
  635. <div @click="maybe = count"/>
  636. <div @click="lett = count"/>
  637. <div @click="v += 1"/>
  638. <div @click="v -= 1"/>
  639. <div @click="() => {
  640. let a = '' + lett
  641. v = a
  642. }"/>
  643. <div @click="() => {
  644. // nested scopes
  645. (()=>{
  646. let x = a
  647. (()=>{
  648. let z = x
  649. let z2 = z
  650. })
  651. let lz = z
  652. })
  653. v = a
  654. }"/>
  655. </template>
  656. `,
  657. { inlineTemplate: true }
  658. )
  659. // known const ref: set value
  660. expect(content).toMatch(`count.value = 1`)
  661. // const but maybe ref: only assign after check
  662. expect(content).toMatch(`maybe.value = count.value`)
  663. // let: handle both cases
  664. expect(content).toMatch(
  665. `_isRef(lett) ? lett.value = count.value : lett = count.value`
  666. )
  667. expect(content).toMatch(`_isRef(v) ? v.value += 1 : v += 1`)
  668. expect(content).toMatch(`_isRef(v) ? v.value -= 1 : v -= 1`)
  669. expect(content).toMatch(`_isRef(v) ? v.value = a : v = a`)
  670. expect(content).toMatch(`_isRef(v) ? v.value = _ctx.a : v = _ctx.a`)
  671. assertCode(content)
  672. })
  673. test('template update expression codegen', () => {
  674. const { content } = compile(
  675. `<script setup>
  676. import { ref } from 'vue'
  677. const count = ref(0)
  678. const maybe = foo()
  679. let lett = 1
  680. </script>
  681. <template>
  682. <div @click="count++"/>
  683. <div @click="--count"/>
  684. <div @click="maybe++"/>
  685. <div @click="--maybe"/>
  686. <div @click="lett++"/>
  687. <div @click="--lett"/>
  688. </template>
  689. `,
  690. { inlineTemplate: true }
  691. )
  692. // known const ref: set value
  693. expect(content).toMatch(`count.value++`)
  694. expect(content).toMatch(`--count.value`)
  695. // const but maybe ref (non-ref case ignored)
  696. expect(content).toMatch(`maybe.value++`)
  697. expect(content).toMatch(`--maybe.value`)
  698. // let: handle both cases
  699. expect(content).toMatch(`_isRef(lett) ? lett.value++ : lett++`)
  700. expect(content).toMatch(`_isRef(lett) ? --lett.value : --lett`)
  701. assertCode(content)
  702. })
  703. test('template destructure assignment codegen', () => {
  704. const { content } = compile(
  705. `<script setup>
  706. import { ref } from 'vue'
  707. const val = {}
  708. const count = ref(0)
  709. const maybe = foo()
  710. let lett = 1
  711. </script>
  712. <template>
  713. <div @click="({ count } = val)"/>
  714. <div @click="[maybe] = val"/>
  715. <div @click="({ lett } = val)"/>
  716. </template>
  717. `,
  718. { inlineTemplate: true }
  719. )
  720. // known const ref: set value
  721. expect(content).toMatch(`({ count: count.value } = val)`)
  722. // const but maybe ref (non-ref case ignored)
  723. expect(content).toMatch(`[maybe.value] = val`)
  724. // let: assumes non-ref
  725. expect(content).toMatch(`{ lett: lett } = val`)
  726. assertCode(content)
  727. })
  728. test('ssr codegen', () => {
  729. const { content } = compile(
  730. `
  731. <script setup>
  732. import { ref } from 'vue'
  733. const count = ref(0)
  734. </script>
  735. <template>
  736. <div>{{ count }}</div>
  737. <div>static</div>
  738. </template>
  739. <style>
  740. div { color: v-bind(count) }
  741. </style>
  742. `,
  743. {
  744. inlineTemplate: true,
  745. templateOptions: {
  746. ssr: true
  747. }
  748. }
  749. )
  750. expect(content).toMatch(`\n __ssrInlineRender: true,\n`)
  751. expect(content).toMatch(`return (_ctx, _push`)
  752. expect(content).toMatch(`ssrInterpolate`)
  753. expect(content).not.toMatch(`useCssVars`)
  754. expect(content).toMatch(`"--${mockId}-count": (count.value)`)
  755. assertCode(content)
  756. })
  757. test('the v-for wrapped in parentheses can be correctly parsed & inline is false', () => {
  758. expect(() =>
  759. compile(
  760. `
  761. <script setup lang="ts">
  762. import { ref } from 'vue'
  763. const stacks = ref([])
  764. </script>
  765. <template>
  766. <div v-for="({ file: efile }) of stacks"></div>
  767. </template>
  768. `,
  769. {
  770. inlineTemplate: false
  771. }
  772. )
  773. ).not.toThrowError()
  774. })
  775. })
  776. describe('with TypeScript', () => {
  777. test('hoist type declarations', () => {
  778. const { content } = compile(`
  779. <script setup lang="ts">
  780. export interface Foo {}
  781. type Bar = {}
  782. </script>`)
  783. assertCode(content)
  784. })
  785. test('runtime Enum', () => {
  786. const { content, bindings } = compile(
  787. `<script setup lang="ts">
  788. enum Foo { A = 123 }
  789. </script>`
  790. )
  791. assertCode(content)
  792. expect(bindings).toStrictEqual({
  793. Foo: BindingTypes.LITERAL_CONST
  794. })
  795. })
  796. test('runtime Enum in normal script', () => {
  797. const { content, bindings } = compile(
  798. `<script lang="ts">
  799. export enum D { D = "D" }
  800. const enum C { C = "C" }
  801. enum B { B = "B" }
  802. </script>
  803. <script setup lang="ts">
  804. enum Foo { A = 123 }
  805. </script>`
  806. )
  807. assertCode(content)
  808. expect(bindings).toStrictEqual({
  809. D: BindingTypes.LITERAL_CONST,
  810. C: BindingTypes.LITERAL_CONST,
  811. B: BindingTypes.LITERAL_CONST,
  812. Foo: BindingTypes.LITERAL_CONST
  813. })
  814. })
  815. test('const Enum', () => {
  816. const { content, bindings } = compile(
  817. `<script setup lang="ts">
  818. const enum Foo { A = 123 }
  819. </script>`,
  820. { hoistStatic: true }
  821. )
  822. assertCode(content)
  823. expect(bindings).toStrictEqual({
  824. Foo: BindingTypes.LITERAL_CONST
  825. })
  826. })
  827. test('import type', () => {
  828. const { content } = compile(
  829. `<script setup lang="ts">
  830. import type { Foo } from './main.ts'
  831. import { type Bar, Baz } from './main.ts'
  832. </script>`
  833. )
  834. expect(content).toMatch(`return { get Baz() { return Baz } }`)
  835. assertCode(content)
  836. })
  837. })
  838. describe('async/await detection', () => {
  839. function assertAwaitDetection(code: string, shouldAsync = true) {
  840. const { content } = compile(`<script setup>${code}</script>`, {
  841. reactivityTransform: true
  842. })
  843. if (shouldAsync) {
  844. expect(content).toMatch(`let __temp, __restore`)
  845. }
  846. expect(content).toMatch(`${shouldAsync ? `async ` : ``}setup(`)
  847. assertCode(content)
  848. return content
  849. }
  850. test('expression statement', () => {
  851. assertAwaitDetection(`await foo`)
  852. })
  853. test('variable', () => {
  854. assertAwaitDetection(`const a = 1 + (await foo)`)
  855. })
  856. test('ref', () => {
  857. assertAwaitDetection(`let a = $ref(1 + (await foo))`)
  858. })
  859. // #4448
  860. test('nested await', () => {
  861. assertAwaitDetection(`await (await foo)`)
  862. assertAwaitDetection(`await ((await foo))`)
  863. assertAwaitDetection(`await (await (await foo))`)
  864. })
  865. // should prepend semicolon
  866. test('nested leading await in expression statement', () => {
  867. const code = assertAwaitDetection(`foo()\nawait 1 + await 2`)
  868. expect(code).toMatch(`foo()\n;(`)
  869. })
  870. // #4596 should NOT prepend semicolon
  871. test('single line conditions', () => {
  872. const code = assertAwaitDetection(`if (false) await foo()`)
  873. expect(code).not.toMatch(`if (false) ;(`)
  874. })
  875. test('nested statements', () => {
  876. assertAwaitDetection(`if (ok) { await foo } else { await bar }`)
  877. })
  878. test('multiple `if` nested statements', () => {
  879. assertAwaitDetection(`if (ok) {
  880. let a = 'foo'
  881. await 0 + await 1
  882. await 2
  883. } else if (a) {
  884. await 10
  885. if (b) {
  886. await 0 + await 1
  887. } else {
  888. let a = 'foo'
  889. await 2
  890. }
  891. if (b) {
  892. await 3
  893. await 4
  894. }
  895. } else {
  896. await 5
  897. }`)
  898. })
  899. test('multiple `if while` nested statements', () => {
  900. assertAwaitDetection(`if (ok) {
  901. while (d) {
  902. await 5
  903. }
  904. while (d) {
  905. await 5
  906. await 6
  907. if (c) {
  908. let f = 10
  909. 10 + await 7
  910. } else {
  911. await 8
  912. await 9
  913. }
  914. }
  915. }`)
  916. })
  917. test('multiple `if for` nested statements', () => {
  918. assertAwaitDetection(`if (ok) {
  919. for (let a of [1,2,3]) {
  920. await a
  921. }
  922. for (let a of [1,2,3]) {
  923. await a
  924. await a
  925. }
  926. }`)
  927. })
  928. test('should ignore await inside functions', () => {
  929. // function declaration
  930. assertAwaitDetection(`async function foo() { await bar }`, false)
  931. // function expression
  932. assertAwaitDetection(`const foo = async () => { await bar }`, false)
  933. // object method
  934. assertAwaitDetection(`const obj = { async method() { await bar }}`, false)
  935. // class method
  936. assertAwaitDetection(
  937. `const cls = class Foo { async method() { await bar }}`,
  938. false
  939. )
  940. })
  941. })
  942. describe('errors', () => {
  943. test('<script> and <script setup> must have same lang', () => {
  944. expect(() =>
  945. compile(`<script>foo()</script><script setup lang="ts">bar()</script>`)
  946. ).toThrow(`<script> and <script setup> must have the same language type`)
  947. })
  948. const moduleErrorMsg = `cannot contain ES module exports`
  949. test('non-type named exports', () => {
  950. expect(() =>
  951. compile(`<script setup>
  952. export const a = 1
  953. </script>`)
  954. ).toThrow(moduleErrorMsg)
  955. expect(() =>
  956. compile(`<script setup>
  957. export * from './foo'
  958. </script>`)
  959. ).toThrow(moduleErrorMsg)
  960. expect(() =>
  961. compile(`<script setup>
  962. const bar = 1
  963. export { bar as default }
  964. </script>`)
  965. ).toThrow(moduleErrorMsg)
  966. })
  967. test('defineProps/Emit() referencing local var', () => {
  968. expect(() =>
  969. compile(`<script setup>
  970. let bar = 1
  971. defineProps({
  972. foo: {
  973. default: () => bar
  974. }
  975. })
  976. </script>`)
  977. ).toThrow(`cannot reference locally declared variables`)
  978. expect(() =>
  979. compile(`<script setup>
  980. let bar = 'hello'
  981. defineEmits([bar])
  982. </script>`)
  983. ).toThrow(`cannot reference locally declared variables`)
  984. // #4644
  985. expect(() =>
  986. compile(`
  987. <script>const bar = 1</script>
  988. <script setup>
  989. defineProps({
  990. foo: {
  991. default: () => bar
  992. }
  993. })
  994. </script>`)
  995. ).not.toThrow(`cannot reference locally declared variables`)
  996. })
  997. test('should allow defineProps/Emit() referencing scope var', () => {
  998. assertCode(
  999. compile(`<script setup>
  1000. const bar = 1
  1001. defineProps({
  1002. foo: {
  1003. default: bar => bar + 1
  1004. }
  1005. })
  1006. defineEmits({
  1007. foo: bar => bar > 1
  1008. })
  1009. </script>`).content
  1010. )
  1011. })
  1012. test('should allow defineProps/Emit() referencing imported binding', () => {
  1013. assertCode(
  1014. compile(`<script setup>
  1015. import { bar } from './bar'
  1016. defineProps({
  1017. foo: {
  1018. default: () => bar
  1019. }
  1020. })
  1021. defineEmits({
  1022. foo: () => bar > 1
  1023. })
  1024. </script>`).content
  1025. )
  1026. })
  1027. })
  1028. })
  1029. describe('SFC analyze <script> bindings', () => {
  1030. it('can parse decorators syntax in typescript block', () => {
  1031. const { scriptAst } = compile(`
  1032. <script lang="ts">
  1033. import { Options, Vue } from 'vue-class-component';
  1034. @Options({
  1035. components: {
  1036. HelloWorld,
  1037. },
  1038. props: ['foo', 'bar']
  1039. })
  1040. export default class Home extends Vue {}
  1041. </script>
  1042. `)
  1043. expect(scriptAst).toBeDefined()
  1044. })
  1045. it('recognizes props array declaration', () => {
  1046. const { bindings } = compile(`
  1047. <script>
  1048. export default {
  1049. props: ['foo', 'bar']
  1050. }
  1051. </script>
  1052. `)
  1053. expect(bindings).toStrictEqual({
  1054. foo: BindingTypes.PROPS,
  1055. bar: BindingTypes.PROPS
  1056. })
  1057. expect(bindings!.__isScriptSetup).toBe(false)
  1058. })
  1059. it('recognizes props object declaration', () => {
  1060. const { bindings } = compile(`
  1061. <script>
  1062. export default {
  1063. props: {
  1064. foo: String,
  1065. bar: {
  1066. type: String,
  1067. },
  1068. baz: null,
  1069. qux: [String, Number]
  1070. }
  1071. }
  1072. </script>
  1073. `)
  1074. expect(bindings).toStrictEqual({
  1075. foo: BindingTypes.PROPS,
  1076. bar: BindingTypes.PROPS,
  1077. baz: BindingTypes.PROPS,
  1078. qux: BindingTypes.PROPS
  1079. })
  1080. expect(bindings!.__isScriptSetup).toBe(false)
  1081. })
  1082. it('recognizes setup return', () => {
  1083. const { bindings } = compile(`
  1084. <script>
  1085. const bar = 2
  1086. export default {
  1087. setup() {
  1088. return {
  1089. foo: 1,
  1090. bar
  1091. }
  1092. }
  1093. }
  1094. </script>
  1095. `)
  1096. expect(bindings).toStrictEqual({
  1097. foo: BindingTypes.SETUP_MAYBE_REF,
  1098. bar: BindingTypes.SETUP_MAYBE_REF
  1099. })
  1100. expect(bindings!.__isScriptSetup).toBe(false)
  1101. })
  1102. it('recognizes exported vars', () => {
  1103. const { bindings } = compile(`
  1104. <script>
  1105. export const foo = 2
  1106. </script>
  1107. <script setup>
  1108. console.log(foo)
  1109. </script>
  1110. `)
  1111. expect(bindings).toStrictEqual({
  1112. foo: BindingTypes.LITERAL_CONST
  1113. })
  1114. })
  1115. it('recognizes async setup return', () => {
  1116. const { bindings } = compile(`
  1117. <script>
  1118. const bar = 2
  1119. export default {
  1120. async setup() {
  1121. return {
  1122. foo: 1,
  1123. bar
  1124. }
  1125. }
  1126. }
  1127. </script>
  1128. `)
  1129. expect(bindings).toStrictEqual({
  1130. foo: BindingTypes.SETUP_MAYBE_REF,
  1131. bar: BindingTypes.SETUP_MAYBE_REF
  1132. })
  1133. expect(bindings!.__isScriptSetup).toBe(false)
  1134. })
  1135. it('recognizes data return', () => {
  1136. const { bindings } = compile(`
  1137. <script>
  1138. const bar = 2
  1139. export default {
  1140. data() {
  1141. return {
  1142. foo: null,
  1143. bar
  1144. }
  1145. }
  1146. }
  1147. </script>
  1148. `)
  1149. expect(bindings).toStrictEqual({
  1150. foo: BindingTypes.DATA,
  1151. bar: BindingTypes.DATA
  1152. })
  1153. })
  1154. it('recognizes methods', () => {
  1155. const { bindings } = compile(`
  1156. <script>
  1157. export default {
  1158. methods: {
  1159. foo() {}
  1160. }
  1161. }
  1162. </script>
  1163. `)
  1164. expect(bindings).toStrictEqual({ foo: BindingTypes.OPTIONS })
  1165. })
  1166. it('recognizes computeds', () => {
  1167. const { bindings } = compile(`
  1168. <script>
  1169. export default {
  1170. computed: {
  1171. foo() {},
  1172. bar: {
  1173. get() {},
  1174. set() {},
  1175. }
  1176. }
  1177. }
  1178. </script>
  1179. `)
  1180. expect(bindings).toStrictEqual({
  1181. foo: BindingTypes.OPTIONS,
  1182. bar: BindingTypes.OPTIONS
  1183. })
  1184. })
  1185. it('recognizes injections array declaration', () => {
  1186. const { bindings } = compile(`
  1187. <script>
  1188. export default {
  1189. inject: ['foo', 'bar']
  1190. }
  1191. </script>
  1192. `)
  1193. expect(bindings).toStrictEqual({
  1194. foo: BindingTypes.OPTIONS,
  1195. bar: BindingTypes.OPTIONS
  1196. })
  1197. })
  1198. it('recognizes injections object declaration', () => {
  1199. const { bindings } = compile(`
  1200. <script>
  1201. export default {
  1202. inject: {
  1203. foo: {},
  1204. bar: {},
  1205. }
  1206. }
  1207. </script>
  1208. `)
  1209. expect(bindings).toStrictEqual({
  1210. foo: BindingTypes.OPTIONS,
  1211. bar: BindingTypes.OPTIONS
  1212. })
  1213. })
  1214. it('works for mixed bindings', () => {
  1215. const { bindings } = compile(`
  1216. <script>
  1217. export default {
  1218. inject: ['foo'],
  1219. props: {
  1220. bar: String,
  1221. },
  1222. setup() {
  1223. return {
  1224. baz: null,
  1225. }
  1226. },
  1227. data() {
  1228. return {
  1229. qux: null
  1230. }
  1231. },
  1232. methods: {
  1233. quux() {}
  1234. },
  1235. computed: {
  1236. quuz() {}
  1237. }
  1238. }
  1239. </script>
  1240. `)
  1241. expect(bindings).toStrictEqual({
  1242. foo: BindingTypes.OPTIONS,
  1243. bar: BindingTypes.PROPS,
  1244. baz: BindingTypes.SETUP_MAYBE_REF,
  1245. qux: BindingTypes.DATA,
  1246. quux: BindingTypes.OPTIONS,
  1247. quuz: BindingTypes.OPTIONS
  1248. })
  1249. })
  1250. it('works for script setup', () => {
  1251. const { bindings } = compile(`
  1252. <script setup>
  1253. import { ref as r } from 'vue'
  1254. defineProps({
  1255. foo: String
  1256. })
  1257. const a = r(1)
  1258. let b = 2
  1259. const c = 3
  1260. const { d } = someFoo()
  1261. let { e } = someBar()
  1262. </script>
  1263. `)
  1264. expect(bindings).toStrictEqual({
  1265. r: BindingTypes.SETUP_CONST,
  1266. a: BindingTypes.SETUP_REF,
  1267. b: BindingTypes.SETUP_LET,
  1268. c: BindingTypes.LITERAL_CONST,
  1269. d: BindingTypes.SETUP_MAYBE_REF,
  1270. e: BindingTypes.SETUP_LET,
  1271. foo: BindingTypes.PROPS
  1272. })
  1273. })
  1274. describe('auto name inference', () => {
  1275. test('basic', () => {
  1276. const { content } = compile(
  1277. `<script setup>const a = 1</script>
  1278. <template>{{ a }}</template>`,
  1279. undefined,
  1280. {
  1281. filename: 'FooBar.vue'
  1282. }
  1283. )
  1284. expect(content).toMatch(`export default {
  1285. __name: 'FooBar'`)
  1286. assertCode(content)
  1287. })
  1288. test('do not overwrite manual name (object)', () => {
  1289. const { content } = compile(
  1290. `<script>
  1291. export default {
  1292. name: 'Baz'
  1293. }
  1294. </script>
  1295. <script setup>const a = 1</script>
  1296. <template>{{ a }}</template>`,
  1297. undefined,
  1298. {
  1299. filename: 'FooBar.vue'
  1300. }
  1301. )
  1302. expect(content).not.toMatch(`name: 'FooBar'`)
  1303. expect(content).toMatch(`name: 'Baz'`)
  1304. assertCode(content)
  1305. })
  1306. test('do not overwrite manual name (call)', () => {
  1307. const { content } = compile(
  1308. `<script>
  1309. import { defineComponent } from 'vue'
  1310. export default defineComponent({
  1311. name: 'Baz'
  1312. })
  1313. </script>
  1314. <script setup>const a = 1</script>
  1315. <template>{{ a }}</template>`,
  1316. undefined,
  1317. {
  1318. filename: 'FooBar.vue'
  1319. }
  1320. )
  1321. expect(content).not.toMatch(`name: 'FooBar'`)
  1322. expect(content).toMatch(`name: 'Baz'`)
  1323. assertCode(content)
  1324. })
  1325. })
  1326. })
  1327. describe('SFC genDefaultAs', () => {
  1328. test('normal <script> only', () => {
  1329. const { content } = compile(
  1330. `<script>
  1331. export default {}
  1332. </script>`,
  1333. {
  1334. genDefaultAs: '_sfc_'
  1335. }
  1336. )
  1337. expect(content).not.toMatch('export default')
  1338. expect(content).toMatch(`const _sfc_ = {}`)
  1339. assertCode(content)
  1340. })
  1341. test('normal <script> w/ cssVars', () => {
  1342. const { content } = compile(
  1343. `<script>
  1344. export default {}
  1345. </script>
  1346. <style>
  1347. .foo { color: v-bind(x) }
  1348. </style>`,
  1349. {
  1350. genDefaultAs: '_sfc_'
  1351. }
  1352. )
  1353. expect(content).not.toMatch('export default')
  1354. expect(content).not.toMatch('__default__')
  1355. expect(content).toMatch(`const _sfc_ = {}`)
  1356. assertCode(content)
  1357. })
  1358. test('<script> + <script setup>', () => {
  1359. const { content } = compile(
  1360. `<script>
  1361. export default {}
  1362. </script>
  1363. <script setup>
  1364. const a = 1
  1365. </script>`,
  1366. {
  1367. genDefaultAs: '_sfc_'
  1368. }
  1369. )
  1370. expect(content).not.toMatch('export default')
  1371. expect(content).toMatch(
  1372. `const _sfc_ = /*#__PURE__*/Object.assign(__default__`
  1373. )
  1374. assertCode(content)
  1375. })
  1376. test('<script> + <script setup>', () => {
  1377. const { content } = compile(
  1378. `<script>
  1379. export default {}
  1380. </script>
  1381. <script setup>
  1382. const a = 1
  1383. </script>`,
  1384. {
  1385. genDefaultAs: '_sfc_'
  1386. }
  1387. )
  1388. expect(content).not.toMatch('export default')
  1389. expect(content).toMatch(
  1390. `const _sfc_ = /*#__PURE__*/Object.assign(__default__`
  1391. )
  1392. assertCode(content)
  1393. })
  1394. test('<script setup> only', () => {
  1395. const { content } = compile(
  1396. `<script setup>
  1397. const a = 1
  1398. </script>`,
  1399. {
  1400. genDefaultAs: '_sfc_'
  1401. }
  1402. )
  1403. expect(content).not.toMatch('export default')
  1404. expect(content).toMatch(`const _sfc_ = {\n setup`)
  1405. assertCode(content)
  1406. })
  1407. test('<script setup> only w/ ts', () => {
  1408. const { content } = compile(
  1409. `<script setup lang="ts">
  1410. const a = 1
  1411. </script>`,
  1412. {
  1413. genDefaultAs: '_sfc_'
  1414. }
  1415. )
  1416. expect(content).not.toMatch('export default')
  1417. expect(content).toMatch(`const _sfc_ = /*#__PURE__*/_defineComponent(`)
  1418. assertCode(content)
  1419. })
  1420. test('<script> + <script setup> w/ ts', () => {
  1421. const { content } = compile(
  1422. `<script lang="ts">
  1423. export default {}
  1424. </script>
  1425. <script setup lang="ts">
  1426. const a = 1
  1427. </script>`,
  1428. {
  1429. genDefaultAs: '_sfc_'
  1430. }
  1431. )
  1432. expect(content).not.toMatch('export default')
  1433. expect(content).toMatch(
  1434. `const _sfc_ = /*#__PURE__*/_defineComponent({\n ...__default__`
  1435. )
  1436. assertCode(content)
  1437. })
  1438. test('binding type for edge cases', () => {
  1439. const { bindings } = compile(
  1440. `<script setup lang="ts">
  1441. import { toRef } from 'vue'
  1442. const props = defineProps<{foo: string}>()
  1443. const foo = toRef(() => props.foo)
  1444. </script>`
  1445. )
  1446. expect(bindings).toStrictEqual({
  1447. toRef: BindingTypes.SETUP_CONST,
  1448. props: BindingTypes.SETUP_REACTIVE_CONST,
  1449. foo: BindingTypes.SETUP_REF
  1450. })
  1451. })
  1452. })